오늘은 기존에 useState
와 useEffect
를 사용하여 json-server와 통신하던 투두리스트 애플리케이션을 Tanstack Query(구 React Query)를 이용하여 리팩터링했습니다. Tanstack Query를 사용하면 비동기 상태 관리를 더욱 효율적으로 할 수 있습니다. 아래는 리팩터링 과정을 정리한 내용입니다.
먼저, Tanstack Query를 사용하기 위해 패키지를 설치합니다.
npm install @tanstack/react-query
또한, QueryClient와 QueryClientProvider를 설정하여 애플리케이션 전반에서 Tanstack Query를 사용할 수 있도록 합니다.
// src/main.js
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import Router from "./shared/Router";
const queryClient = new QueryClient();
function App() {
return (
<QueryClientProvider client={queryClient}>
<Router />
</QueryClientProvider>
);
}
export default App;
Detail
컴포넌트에서 useState
와 useEffect
를 사용하던 부분을 useQuery
로 리팩터링합니다. useQuery
는 서버에서 데이터를 불러오는 비동기 작업을 쉽게 처리할 수 있게 해줍니다. useQuery
훅은 데이터 로딩 상태와 오류 상태를 자동으로 관리해주기 때문에, 코드가 간결해지고 유지보수가 쉬워집니다.
// src/components/Detail.js
import { useQuery } from '@tanstack/react-query';
import { useParams } from 'react-router-dom';
import { todoApi } from '../api/todos';
function Detail() {
const { id } = useParams();
const { data: todo, error, isLoading } = useQuery(['todo', id], () =>
todoApi.get(`/todos/${id}`).then((res) => res.data)
);
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div>
<h2>{todo.title}</h2>
<p>{todo.contents}</p>
<p>{todo.isCompleted ? '완료' : '미완료'}</p>
</div>
);
}
export default Detail;
TodoForm
컴포넌트에서는 useState
와 useEffect
대신 useMutation
을 사용합니다. useMutation
은 서버에 데이터를 전송하는 비동기 작업을 처리하는 데 유용합니다.
// src/components/TodoForm.js
import { useState } from 'react';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { todoApi } from '../api/todos';
export default function TodoForm() {
const [title, setTitle] = useState('');
const [contents, setContents] = useState('');
const queryClient = useQueryClient();
const mutation = useMutation(
{
mutationFn: async (newTodo) => {
await todoApi.post('/todos', newTodo);
},
onSuccess: () => {
queryClient.invalidateQueries('todos');
},
}
);
const handleAddTodo = (e) => {
e.preventDefault();
mutation.mutate({
id: Date.now().toString(),
title,
contents,
isCompleted: false,
createdAt: Date.now(),
});
setTitle('');
setContents('');
};
return (
<form onSubmit={handleAddTodo}>
<label htmlFor="title">제목:</label>
<input
type="text"
id="title"
name="title"
value={title}
onChange={(e) => setTitle(e.target.value)}
required
/>
<label htmlFor="contents">내용:</label>
<input
id="contents"
name="contents"
value={contents}
onChange={(e) => setContents(e.target.value)}
required
/>
<button type="submit">추가하기</button>
</form>
);
}
리팩터링 과정에서 useMutation
을 사용할 때, mutationFn
키를 누락하여 오류가 발생했습니다. mutationFn
키는 useMutation
훅에 필수적으로 포함되어야 하며, 이 키는 실제로 데이터를 조작하는 함수로 설정해야 합니다. 아래와 같은 오류 메시지를 확인할 수 있었습니다:
Error: Expected 'mutationFn' to be a function. Found 'undefined'.
이 문제는 useMutation
훅을 설정할 때 mutationFn
키와 함께 함수를 정의하여 해결할 수 있습니다. mutationFn
키를 통해 서버와의 비동기 통신을 원활하게 할 수 있으며, 이를 통해 데이터의 변경을 처리합니다. 따라서, mutationFn
키의 누락은 비동기 통신의 실패로 이어질 수 있습니다.
Tanstack Query를 사용하여 투두리스트 애플리케이션을 리팩터링하면서 비동기 상태 관리를 더 간편하게 할 수 있었습니다. useQuery
와 useMutation
훅을 사용하여 데이터 가져오기와 전송 작업을 처리하니 코드가 더욱 직관적이고 유지보수가 쉬워졌습니다. 앞으로도 Tanstack Query를 적극 활용하여 다른 프로젝트에서도 효율적인 비동기 상태 관리를 구현해 볼 계획입니다.