6-24 TIL

이세영·2024년 6월 24일
1
post-thumbnail

Tanstack Query를 이용한 투두리스트 리팩터링

오늘은 기존에 useStateuseEffect를 사용하여 json-server와 통신하던 투두리스트 애플리케이션을 Tanstack Query(구 React Query)를 이용하여 리팩터링했습니다. Tanstack Query를 사용하면 비동기 상태 관리를 더욱 효율적으로 할 수 있습니다. 아래는 리팩터링 과정을 정리한 내용입니다.

1. 프로젝트 세팅

먼저, 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;

2. Detail 컴포넌트 리팩터링

Detail 컴포넌트에서 useStateuseEffect를 사용하던 부분을 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;

3. TodoForm 컴포넌트 리팩터링

TodoForm 컴포넌트에서는 useStateuseEffect 대신 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를 사용하여 투두리스트 애플리케이션을 리팩터링하면서 비동기 상태 관리를 더 간편하게 할 수 있었습니다. useQueryuseMutation 훅을 사용하여 데이터 가져오기와 전송 작업을 처리하니 코드가 더욱 직관적이고 유지보수가 쉬워졌습니다. 앞으로도 Tanstack Query를 적극 활용하여 다른 프로젝트에서도 효율적인 비동기 상태 관리를 구현해 볼 계획입니다.

profile
블로그 관리 하루에 한번씩 도전!

0개의 댓글