
내장 웹 API
Fetch API는 웹 브라우저에 내장된 API로, 브라우저 환경에서 JavaScript를 사용해 네트워크 요청을 생성하고 응답을 처리할 수 있다.
Promise 기반
Fetch API는 Promise 기반으로 작동하며, 비동기적으로 HTTP 요청을 처리한다.
요청 및 응답 객체
Fetch API를 사용하면 Request와 Response 객체를 생성해 요청 및 응답을 다룰 수 있다. 이를 통해 요청 헤더, 요청 본문, 응답 헤더, 응답 본문 등을 자유럽게 조작할 수 있다.
=> 이 외에도 CORS 지원, 네트워크 요청 조작, JSON 지원 등 다양한 특징이 있다.
일단, useState 훅을 사용해 데이터, 로딩 상태, 에러 상태를 관리할 수 있는 상태 변수를 선언하고, useEffect 훅을 통해 컴포넌트가 마운트될 때 데이터를 가져오는 비동기 함수를 호출한다.
fetchData 함수에서 먼저 GET 요청을 보내 데이터를 가져오고, 그 후 POST 요청을 보내 새로운 포스트를 추가한다.
각각의 요청에는 응답이 성공하면 해당 데이터를 처리하고, 실패하면 오류를 처리한다. 마지막으로 데이터를 성공적으로 가져오면, 로딩 상태를 false로 변경하여 데이터를 화면에 출력한다.
// FetchApiTest.jsx
import React, { useState, useEffect } from 'react';
const FetchApiTest = () => {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
// GET 요청
const getResponse = await fetch('https://api.example.com/data');
if (!getResponse.ok) {
throw new Error('네트워크 응답 에러 발생');
}
const getData = await getResponse.json();
setData(getData);
// POST 요청
const postData = {
title: 'New Post',
body: 'This is a new post',
userId: 10,
};
const postResponse = await fetch('https://api.example.com/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
// 필요에 따라 추가적인 헤더 설정 가능
},
// 요청 본문에 JSON 형식의 문자열로 변환된 데이터 전달
body: JSON.stringify(postData),
});
if (!postResponse.ok) {
throw new Error('POST 요청 실패');
}
const postDataResponse = await postResponse.json();
console.log('새로운 포스트 추가:', postDataResponse);
} catch (error) {
setError(error);
} finally {
setLoading(false);
}
};
fetchData();
}, []);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error fetching data</div>;
return (
<>
<h1>Data</h1>
<ul>
{data.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
</>
);
};
export default FetchApiTest;
Axios는 HTTP 클라이언트 라이브러리로, 주로 서버와의 HTTP 요청을 처리하고 데이터를 가져오는데 사용된다. 리액트에서 API를 호출하고 데이터를 처리할 때 많이 사용된다.
Axios는 단순히 HTTP 요청을 보내고 받는 역할에 초점이 되어 있고, 복잡한 요청을 보내고 응답을 처리할 때 유용하나, 데이터 관리나 캐싱 등의 기능은 제공하지 않는다.
간편한 API 사용
Axios는 GET, POST, PUT, DELETE 등의 메서드를 사용해 다양한 HTTP 요청을 수행할 수 있다. 각 메서드는 직관적이고 사용하기 쉬운 API를 제공한다.
브라우저와 Node.js 모두 지원
Axios는 브라우저 및 Node.js 환경에서 모두 사용할 수 있다. 이는 클라이언트 측 및 서버 측에서 일관된 방식으로 HTTP 요청을 처리할 수 있게 된다.
간결하고 확장 가능한 설정
Axios는 HTTP 요청에 대한 다양한 설정은 제공한다. 예를 들어, 타임아웃 설정, 헤더 구성, 인증 설정 등이 포함되어 있다.
요청 및 응답 인터셉터
Axios는 요청 및 응답을 인터셉터하고 처리할 수 있는 기능을 제공한다. 이를 통해 요청이나 응답을 변경하거나, 요청이 발생하기 전에 미리 처리할 수 있다.
자동으로 JSON 데이터 직렬화 및 파싱
Axios는 기본적으로 JSON 데이터를 자동으로 직렬화하고 응답에서 파싱한다. JSON 형식의 데이터를 주고받을 때 별도의 직렬화 및 파싱 로직을 구현할 필요가 없어 편리하다.
Promise 기반
Axios는 Promise를 반환하므로 비동기 코드를 처리할 때 더 편리하고 유연하게 사용할 수 있습니다.
=> 이 외에도 CSRF 보호, 프로그래스 이벤트 처리 등 다양한 특징이 있다.
npm install axios
useState 훅을 사용해 데이터, 로딩 상태, 에러 상태를 관리할 수 있는 상태 변수를 선언하고, useEffect 훅을 통해 컴포넌트가 마운트될 때 데이터를 가져오는 비동기 함수를 호출한다.
그 다음, 코드를 자세히 설명해 보자면 fetchData 비동기 함수에서 axios를 사용해 서버에서 데이터를 가져오는 GET 요청을 수행한다. await 키워드를 사용해 axios.get 메서드가 완료될 때가지 기다린 후에 작업을 처리한다.
성공적으로 가져오면, setData 함수를 통해 데이터를 업데이트하고, 오류가 발생하면 catch 블록에서 setError 함수를 통해 에러 상태를 업데이트한다. 마지막으로 요청이 완료되면 로딩 상태를 false로 업데이트한다.
addNewData 비동기 함수 역시 axios를 사용해 서버에 새로운 데이터를 추가하는 POST 요청을 수행한다. 마찬가지 성공적으로 데이터를 추가하면, 응답으로 받은 데이터를 기존 데이터에 추가해 업데이트하고, 오류가 발생하면 catch 블록에서 처리되어 에러 상태를 업데이트한다.
// AxiosTest.jsx
import React, { useState, useEffect } from 'react';
import axios from 'axios';
const AxiosTest = () => {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await axios.get('https://api.example.com/data');
setData(response.data);
} catch (error) {
setError(error);
} finally {
setLoading(false);
}
};
fetchData();
}, []);
const addNewData = () => {
try {
const response = axios.post('https://api.example.com/data', {
// 새로운 데이터 추가
name: 'New Item',
});
// 새로운 데이터 현재 데이터에 추가
setData([...data, response.data]);
} catch (error) {
setError(error);
}
};
if (loading) return <div>Loading...</div>;
if (error) return <div>Error fetching data...</div>;
return (
<>
<h2>Data</h2>
// 새로운 데이터 추가하는 버튼
<button onClick={addNewData}>+ New Data</button>
// 데이터 성공적으로 가져오면 화면에 출력
<ul>
{data.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
</>
);
};
export default AxiosTest;
데이터 가져오기 및 관리
리액트 쿼리는 서버에서 데이터를 가져오는 것을 간편하게 만들어준다. RESTful API, GraphQL 쿼리 등을 사용하여 데이터를 가져올 수 있다.
캐싱
리액트 쿼리는 데이터를 캐싱해 성능을 향상시킨다. 이를 통해 동일한 데이터에 대한 중복 요청을 방지하고, 애플리케이션의 반응성을 향상시킬 수 있다.
상태 관리
리액트 쿼리는 데이터 로딩 상태, 성공 상태, 오류 상태 등을 관리해 UI를 쉽게 업데이트할 수 있다.
자동 갱신
리액트 쿼리는 데이터의 유효성을 유지하고, 필요할 때 자동으로 데이터를 다시 가져오는 기능을 제공한다. 예를 들어 데이터가 만료되었거나 변경되었을 때 자동으로 새로운 데이터를 가져올 수 있다.
npm install react-query
useQuery 훅을 사용해 데이터를 가져오고 관리(GET)한다. 그리고 쿼리의 상태를 관리하고 캐싱된 데이터를 반환한다.
useMutation 훅은 주로 비동기 작업을 수행하고, 그 결과에 따라 데이터를 업데이트하는 데 사용(POST 이외에 DELETE, PUT 등)된다. 리액트 쿼리와 함께 사용되어 외부 API와의 상호 작용을 관리하는 데 유용하다.
아래 예제를 보면, fetchTodos 함수는 useQuery 훅을 통해 Todo 목록을 가져오는 비동기 함수다. 만약 요청이 실패하면 네트워크 오류를 처리하기 위해 throw 문을 사용한다.
addTodo 함수는 새로운 Todo를 추가하기 위해 사용되는 비동기 함수다. POST 요청을 사용하여 새로운 Todo를 서버에 데이터를 전송하고, 요청이 실패하면 todo 추가 실패를 처리하기 위해 throw 문을 사용한다.
useQuery 훅을 사용해 Todo 목록을 가져오고 관리하며, useMutation 훅을 사용해 새로운 Todo를 추가한다. 성공 시에는 새로운 Todo를 추가하고 Todo 목록을 다시 가져온다.
isLoading 및 isError 변수들을 사용하여 데이터가 로딩 중이거나 오류가 발생했을 때 적절한 UI를 렌더링한다. 반대로 새로운 Todo가 성공적으로 추가되면 Todo 목록이 업데이트되어 UI에 반영된다.
// ReactQueryTest.jsx
import React, { useState } from 'react';
import { useQuery, useMutation } from 'react-query';
const fetchTodos = async () => {
const response = await fetch('https://api.example.com/todos');
if (!response.ok) {
throw new Error('네트워크 요청 실패');
}
return response.json();
};
const addTodo = (newTodo) => {
const response = fetch('https://api.example.com/todos', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(newTodo),
});
if (!response.ok) {
throw new Error('todo 추가 실패');
}
return response.json();
};
const ReactQueryTest = () => {
const { data: todos, isLoading, isError, refetch } = useQuery('todos', fetchTodos);
const [newTodo, setNewTodo] = useState('');
const { mutate: addNewTodo, isLoading: isAdding } = useMutation(addTodo, {
onSuccess: () => {
setNewTodo('');
refetch();
},
});
const handleAddTodo = () => {
if (newTodo.trim() !== '') {
addNewTodo({ text: newTodo });
}
};
if (isLoading) return <div>Loading todos...</div>;
if (isError) return <div>Error fetching todos</div>;
return (
<>
<h2>Todo List</h2>
<div>
<input
type="text"
value={newTodo}
onChange={(e) => setNewTodo(e.target.value)}
placeholder="입력해주세요."
/>
<button onClick={handleAddTodo} disabled={isAdding}>
{isAdding ? 'Adding...' : 'Add Todo'}
</button>
</div>
<ul>
{todos.map((todo) => (
<li key={todo.id}>{todo.text}</li>
))}
</ul>
</>
);
};
export default ReactQueryTest;
리덕스, 리덕스 툴킷 등 상태 관리 라이브러리가 있지만, 일반적으로 상태를 관리하기 위해 Axios나 Fetch API는 useState 와 useEffect 훅을 함께 사용한다. 왜? 데이터를 가져오고 상태를 업데이트하는 과정을 수동으로 처리해야하기 때문에!
반면에 React Query는 데이터 가져오기와 관리를 단순화하기 위해 설계되었다.
그래서 usequery 와 useMutation 훅을 사용해 데이터 요청 및 상태 관리를 자동화한다.
이러한 훅들은 데이터 요청 및 상태 관리에 필요한 로직을 내부적으로 처리하여 개발자가 직접 상태를 관리할 필요가 없다.
Fetch API는 Promise 기반이며 간단한 REST API 호출이나 데이터 요청에 유용하고, 기본적인 데이터 요청 및 응답 처리가 필요한 경우에 적절하다.
Axios는 복잡한 데이터 요청이나 다양한 설정이 필요한 경우에 적절하다. 인터셉터를 활용해 요청 및 응답 전에 추가 로직을 수행해야 할 대 유용하다.
React Query는 복잡한 데이터 요청 및 관리가 필요한 경우에 적합하다. 데이터 캐싱이나 자동 갱신, 상태 관리와 같은 고급 기능을 활용하고자 할 때 유용하다.
=> 따라서 React Query는 HTTP 클라이언트 역할을 직접 수행하지 않지만, 가져온 데이터를 관리하고 캐싱하여 애플리케이션 성능을 향상시키니까, 다양한 종류의 HTTP 요청을 보낼 수 있고, 요청과 응답을 처리하기 위한 다양한 기능을 제공하는 axios 라이브러리를 함께 사용하면 굿이다.