학습목표
- 대표적인 비동기 통신 방법인 fetch 와 axios 의 소개 및 예시를 살펴봅니다.
- fetch 와 axios 를 직접 사용해보며 비교합니다. 서로의 장/단점에 대해 이해할 수 있습니다.
Axios
Axios 란?
공식문서에 따르면 axios 란 node.js 와 브라우저를 위한 Promise 기반 http 클라이언트라고 소개하고 있습니다. 다시 말해 http 를 이용해서 서버와 통신하기 위해 사용하는 패키지입니다.
Axios 설치
CRA 를 통해서 새 프로젝트를 생성하고, 터미널에 아래의 명령어를 입력해서 axios 를 설치합니다.
yarn add axios
json-server 설정
API 서버는 직접 만들어 json-server 를 사용합니다.
테스트용 db.json 설정
{
"todos": [
{
"id": "1",
"title": "react"
}
]
}
GET
Axios get
get 은 서버의 데이터를 조회할 때 사용합니다. 기본적인 사용방법은 아래와 같습니다.
// url에는 서버의 url이 들어가고, config에는 기타 여러가지 설정을 추가할 수 있습니다.
// config는 axios 공식문서에서 확인하세요.
axios.get(url[, config]) // GET
json-server API 명세서 확인하기
Axios 를 사용해서 GET 요청 코드를 작성하기에 앞서, 어떤 방식으로 요청해야 할지는 사용하는 json-server 의 방식을 알아보아야 합니다.
다시 말해, Axios 는 GET 요청을 할 수 있도록 도와주는 패키지일 뿐이지, "어떻게 요청을 해야할지?" 와 같은 방식에 대한 확인은 사용할 API 명세서를 보아야 한다는 뜻입니다. 예를 들어 GET 요청을 할 때 path variable 로 해야할지, query 로 보내야 할지는 API 를 만든 사람이 하라는대로 해야 하기 때문이죠.
json-server의 공식문서를 보면, 전체 정보나 상세 정보는 아래와 같이 path variable 로 url 을 작성하면 됩니다.
그리고 filter 와 같은 기능을 위해서 GET 요청을 하고자 할 때는 query 로 보내라고 명시하고 있습니다.
코드로 알아보기
좀 더 실용적인 예시를 코드를 통해 사용방법을 알아보겠습니다. 직접 만든 json-server 에 있는 todos 를 axios 를 이용해 fetching 하고, useState 를 통해서 관리하는 로직입니다. 새로운 프로젝트를 만들어서 코드를 작성해보겠습니다.
// src/App.js
import React, { useEffect, useState } from "react";
import axios from "axios"; // axios import 합니다.
const App = () => {
const [todos, setTodos] = useState(null);
// axios를 통해서 get 요청을 하는 함수를 생성합니다.
// 비동기처리를 해야하므로 async/await 구문을 통해서 처리합니다.
const fetchTodos = async () => {
const { data } = await axios.get("http://localhost:3001/todos");
setTodos(data); // 서버로부터 fetching한 데이터를 useState의 state로 set 합니다.
};
// 생성한 함수를 컴포넌트가 mount 됐을 떄 실행하기 위해 useEffect를 사용합니다.
useEffect(() => {
// effect 구문에 생성한 함수를 넣어 실행합니다.
fetchTodos();
}, []);
// data fetching이 정상적으로 되었는지 콘솔을 통해 확인합니다.
console.log(todos); // App.js:16
return <div>App</div>;
};
export default App;
콘솔로 결과를 확인하니, 생성한 Todos 를 정상적으로 서버에서 가져와서 state 가 set 한 것을 확인할 수 있습니다.
POST
Axios POST
axios.post(url[, data[, config]]) // POST
post 는 보통 서버에 데이터를 추가할 때 사용합니다. 다만, post 요청에 대한 로직은 BE 개발자가 구현하는 것이기 때문에 추가외에 다른 용도로 사용될 수 있지만, 보통은 클라이언트의 데이터를 body 형태로 서버에 보내고자 할 때 사용합니다. 아래 코드를 작성하기에 앞서, GET 에서 본 것과 같이 json-server 의 POST 요청 방식을 확인하고 오시길 바랍니다.
https://www.npmjs.com/package/json-server
json-server
Get a full fake REST API with zero coding in less than 30 seconds. Latest version: 0.17.3, last published: 6 months ago. Start using json-server in your project by running `npm i json-server`. There are 314 other projects in the npm registry using json-ser
www.npmjs.com
코드로 알아보기
GET 코드예시에서 POST 코드가 추가됩니다.
// src/App.jsx
import React, { useEffect, useState } from "react";
import axios from "axios"; // axios import 합니다.
const App = () => {
// 새롭게 생성하는 todo를 관리하는 state
const [todo, setTodo] = useState({
title: "",
});
const [todos, setTodos] = useState(null);
const fetchTodos = async () => {
const { data } = await axios.get("http://localhost:3001/todos");
setTodos(data);
};
const onSubmitHandler = async(todo) => {
//1. 이때 todos는 [{투두하나}]임
await axios.post("http://localhost:3001/todos", todo); // 이때 서버에 있는 todos도 [{투두하나}]임
// 근데 여기서 서버 요청이 끝나고 서버는 [{투두가},{두개임}]
setTodos([...todos, todo]) 2. <-- 만약 이게 없다면, go to useEffect
//4. 새로고침해서 진짜 현재 서버 데이터를 받아오기전에 상태를 똑같이 동기시켜줌
//5. 어떻게보면 유저한테 서버에서 새로 받아온것처럼 속이는거지
};
useEffect(() => {
fetchTodos(); //3. 새로고침해서 여기를 다시 실행해줘야 서버값이 새로 들어옴 e.g) [{투두가},{두개임}]
}, []);
return (
<>
<form
onSubmit={(e) => {
// 👇 submit했을 때 브라우저의 새로고침을 방지합니다.
e.preventDefault();
onSubmitHandler(todo);
}}
>
<input
type="text"
onChange={(ev) => {
const { value } = ev.target;
setTodo({
...todo,
title: value,
});
}}
/>
<button>추가하기</button>
</form>
<div>
{todos?.map((todo) => (
<div key={todo.id}>{todo.title}</div>
))}
</div>
</>
);
};
export default App;
화면에 input 과 button 이 있고, input 에 어떤 값을 넣고 버튼을 클릭했을 대 onSibmitHandler 가 호출됩니다. onSubmitHandler 함수의 목적은 todo 를 body 에 담아 서버로 POST 요청을 보내는 것입니다.
POST 요청을 성공적으로 마쳤다면, 브라우저를 새로고침해보세요. 새롭게 추가한 Todo 가 화면에 보일 것입니다.
DELETE
Axios delete
DELETE 는 저장되어 있는 데이터를 삭제하고자 요청을 보낼 때 사용합니다.
axios.delete(url[, config]) // DELETE
코드로 알아보기
GET, POST 와 함께 코드가 작성됩니다. onClickDeleteButtonHandler 와 map 을 돌린 항목별로 삭제하기 버튼을 추가해줍니다.
// src/App.jsx
import React, { useEffect, useState } from "react";
import axios from "axios";
const App = () => {
const [todo, setTodo] = useState({
title: "",
});
const [todos, setTodos] = useState(null);
const fetchTodos = async () => {
const { data } = await axios.get("http://localhost:3001/todos");
setTodos(data);
};
const onSubmitHandler = (todo) => {
axios.post("http://localhost:3001/todos", todo);
};
// 새롭게 추가한 삭제 버튼 이벤트 핸들러
const onClickDeleteButtonHandler = (todoId) => {
axios.delete(`http://localhost:3001/todos/${todoId}`);
};
useEffect(() => {
fetchTodos();
}, []);
return (
<>
<form
onSubmit={(e) => {
e.preventDefault();
onSubmitHandler(todo);
}}
>
<input
type="text"
onChange={(ev) => {
const { value } = ev.target;
setTodo({
...todo,
title: value,
});
}}
/>
<button>추가하기</button>
</form>
<div>
{todos?.map((todo) => (
<div key={todo.id}>
{todo.title}
{/* 디자인이 요상하긴 하지만..! 삭제 버튼 추가 */}
<button
type="button"
onClick={() => onClickDeleteButtonHandler(todo.id)}
>
삭제하기
</button>
</div>
))}
</div>
</>
);
};
export default App;
DELETE 요청이 성공적으로 이루어졌다면, 브라우저를 새로고침했을 때 삭제한 Todo 가 화면에서 보이지 않는 것을 알 수 있습니다.
PATCH
Axios patch
patch 는 보통 어떤 데이터를 수정하고자 서버에 요청을 보낼 때 사용하는 메서드입니다. 다만, 이것은 http 환경에서 서로가 한 약속이자 문맥이기 때문에 수정을 하고자 반드시 patch, put 을 써야만 하는 것은 아닙니다. BE에 의해서 POST 를 통해서 "수정" 이라는 기능은 충분히 만들 수 있기 때문이죠.
axios.patch(url[, data[, config]]) // PATCH
코드로 알아보기
GET, POST, DELETE 예제에 코드가 추가됩니다. put 은 patch 와 동일한 원리이기 때문에 생략합니다.
Todo 를 수정하기 위해 필요한 데이터는 2개가 있습니다. 수정하고자하는 Todo 의 id, 그리고 수정하고자 하는 값입니다. 수정하고자 하는 값은 기존에 있던 todo 라는 state 를 사용하면 될 것이고, id 는 직접 입력을 해서 url 로 넘겨주는 방식으로 구현했습니다.
보통은 수정기능을 만들 때 직접 id 를 입력받아 처리하는 방식은 거의 없습니다. 다만, 이번 예시에서는 아주 간단한 코드로 기능을 구현하는 것이기 때문에 아래와 같이 처리하겠습니다.
// src/App.jsx
import React, { useEffect, useState } from "react";
import axios from "axios";
const App = () => {
const [todo, setTodo] = useState({
title: "",
});
const [todos, setTodos] = useState(null);
// patch에서 사용할 id, 수정값의 state를 추가
const [targetId, setTargetId] = useState(null);
const [editTodo, setEditTodo] = useState({
title: "",
});
const fetchTodos = async () => {
const { data } = await axios.get("http://localhost:3001/todos");
setTodos(data);
};
const onSubmitHandler = (todo) => {
axios.post("http://localhost:3001/todos", todo);
};
const onClickDeleteButtonHandler = (todoId) => {
axios.delete(`http://localhost:3001/todos/${todoId}`);
};
// 수정버튼 이벤트 핸들러 추가 👇
const onClickEditButtonHandler = (todoId, edit) => {
axios.patch(`http://localhost:3001/todos/${todoId}`, edit);
};
useEffect(() => {
fetchTodos();
}, []);
return (
<>
<form
onSubmit={(e) => {
e.preventDefault();
onSubmitHandler(todo);
}}
>
{/* 👇 수정기능에 필요한 id, 수정값 input2개와 수정하기 버튼을 추가 */}
<div>
<input
type="text"
placeholder="수정하고싶은 Todo ID"
onChange={(ev) => {
setTargetId(ev.target.value);
}}
/>
<input
type="text"
placeholder="수정값 입력"
onChange={(ev) => {
setEditTodo({
...editTodo,
title: ev.target.value,
});
}}
/>
<button
// type='button' 을 추가해야 form의 영향에서 벗어남
type="button"
onClick={() => onClickEditButtonHandler(targetId, editTodo)}
>
수정하기
</button>
</div>
<input
type="text"
onChange={(ev) => {
const { value } = ev.target;
setTodo({
...todo,
title: value,
});
}}
/>
<button>추가하기</button>
</form>
<div>
{todos?.map((todo) => (
<div key={todo.id}>
{/* todo의 아이디를 화면에 표시 */}
{todo.id} :{todo.title}
<button
type="button"
onClick={() => onClickDeleteButtonHandler(todo.id)}
>
삭제하기
</button>
</div>
))}
</div>
</>
);
};
export default App;
.env
아래 주소는 .env 란 무엇이고 왜 사용해야 하는지에 대한 내용입니다. .env 를 이용해서 사용할 API 서버의 IP 또는 URL 을 숨겨서 처리해보겠습니다.
[React] .env (환경변수 관리)
※대학생이 공부하면서 작성한 글입니다※ ※이 글은 CRA로 만들었을 시 기준입니다※ env env는 API key, port, DB 등 민감한 정보를 환경변수에 담아 관리하는 방법이다. 🛑 env 주의사항 🔴 root 폴더
tooo1.tistory.com
fetch
fetch 는 ES6 부터 도입된 JavaScript 내장 라이브러리입니다. Promise 기반 비동기 통신 라이브러리입니다. axios 처럼 데이터를 다루기 쉽고, 내장 라이브러리이기 때문에 별도의 설치 및 import 를 필요로 하지 않습니다.
하지만 다음과 같은 이유로 axios 를 위주로 쓸 예정입니다.
- 미지원 브라우저 존재
- 개발자에게 불친절한 response
- axios 에 비해 부족한 기능
'항해 16기 > Today I Learned' 카테고리의 다른 글
[항해 31일차] TIL_React 심화주차: Thunk (0) | 2023.09.11 |
---|---|
[항해 30일차] TIL_React 심화주차: axios 심화 - instance & interceptor (0) | 2023.09.07 |
[항해 27일차] TIL_React 심화주차: HTTP (0) | 2023.09.07 |
[항해 26일차] TIL_React 심화주차: json-server (0) | 2023.09.07 |
[항해 25일차] TIL_React 심화주차: Redux Toolkit (0) | 2023.09.07 |