2025 . 오은

repo

tanstack-query 이해

문제 정의

프론트엔드 개발 중 서버로부터 데이터를 가져오는 일은 매우 빈번합니다. 이때 매우 유용한 라이브러리가 tanstack-query 였습니다. 그런데 tanstack-query 를 이용해 가져온 데이터를 zustand 등 전역상태관리 라이브러리로 관리하려고 할 때 문제가 발생했습니다. 비동기적일 수 밖에 없는 데이터 fetching 후 바로 데이터를 전역상태에 담으려고 하니 부자연스럽게 느껴졌습니다.

해결 과정

사실 tanstack-query 의 useQuery 로 가져온 data 는 그냥 전역상태와 다름 없었습니다. 굳이 fetch한 데이터를 로컬 전역 상태에 담을 필요가 없고 그냥 어디서든 useQuery 호출 하면 되는 것이었습니다. tanstack-query의 동작방식을 이해하지 못해 발생한 문제였고, 실제 fetching 이 언제 되는지는 dev tool 로 손쉽게 확인이 가능했습니다.

1. tanstack-query 설치 및 설정

  • 프로젝트에 tanstack-query를 설치하고, QueryClient와 QueryClientProvider를 설정했습니다.

    npm install @tanstack/react-query @tanstack/react-query-devtools
    
    // index.tsx
    import React from 'react';
    import ReactDOM from 'react-dom';
    import App from './App';
    import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
    
    const queryClient = new QueryClient();
    
    ReactDOM.render(
      <React.StrictMode>
        <QueryClientProvider client={queryClient}>
          <App />
          <ReactQueryDevtools initialIsOpen={true} />
        </QueryClientProvider>
      </React.StrictMode>,
      document.getElementById('root')
    );
    

2. 기존 Zustand를 통한 데이터 관리 제거

  • Zustand를 사용하여 useQuery의 데이터를 전역 상태에 저장하던 로직을 제거하고, TanStack Query의 useQuery 훅을 직접 활용하도록 수정했습니다.

    // 기존 Zustand 사용 예시
    import create from 'zustand';
    import { useQuery } from '@tanstack/react-query';
    
    const useStore = create((set) => ({
      data: [],
      setData: (newData) => set({ data: newData }),
    }));
    
    const Component = () => {
      const { data, setData } = useStore();
      const { data: queryData, isPending, error, } = useQuery({
          queryKey: ['todos'], 
          queryFn: fetchTodos
      });
      
      React.useEffect(() => {
        if (queryData) setData(queryData);
      }, [queryData, setData]);
      
      // ...
    };
    
    // TanStack Query 도입 후
    import { useQuery } from '@tanstack/react-query';
    
    const Component = () => {
      const { data, isPending, error } = useQuery({
          queryKey: ['todos'], 
          queryFn: fetchTodos
      });
      
      if (isLoading) return <div>Loading...</div>;
      if (error) return <div>Error!</div>;
      
      return (
        <div>
          {data.map(todo => (
            <div key={todo.id}>{todo.title}</div>
          ))}
        </div>
      );
    };
    

결과

tanstack-query를 도입한 후 다음과 같은 개선 효과를 얻었습니다:

  • 전역 상태 관리 단순화: Zustand와 같은 전역 상태 관리 라이브러리를 사용하지 않고도 서버 상태를 효율적으로 관리할 수 있게 되었습니다.
  • 코드 중복 감소: 데이터를 전역 상태에 저장하고 업데이트하는 로직이 사라지면서 코드가 간결해졌습니다.
  • 성능 최적화: TanStack Query의 캐싱과 자동 재페칭 기능을 통해 불필요한 네트워크 요청을 줄이고, 데이터 접근 속도가 향상되었습니다.
  • 개발 생산성 향상: 서버 상태 관리에 대한 복잡한 로직을 라이브러리에 맡김으로써, 비즈니스 로직에 더 집중할 수 있게 되었습니다.

배운 점 (인사이트)

  • tanstack-query의 강력함: tanstack-query는 서버 상태 관리를 효율적으로 처리할 수 있는 강력한 도구임을 깨달았습니다. 이를 통해 전역 상태 관리 라이브러리의 필요성을 줄일 수 있었습니다.
  • 서버 상태와 클라이언트 상태의 명확한 구분: 서버에서 가져오는 데이터는 TanStack Query를 통해 관리하고, 클라이언트에서만 필요한 상태는 Zustand와 같은 라이브러리를 사용하는 것이 더 효과적이라는 점을 이해하게 되었습니다.
  • 라이브러리 선택의 중요성: 프로젝트의 요구사항에 맞는 적절한 라이브러리를 선택함으로써, 상태 관리의 복잡성을 줄이고 개발 효율성을 높일 수 있다는 점을 배웠습니다.
  • 개발 패턴의 이해: 데이터 패칭과 상태 관리에 대한 다양한 패턴을 학습하고, 실제 프로젝트에 적용하면서 이론과 실전의 균형을 맞추는 것이 중요함을 깨달았습니다.