Frontend/Projects

[Toy Project 기록하기 9] React-Query로 서버 상태 관리하기

돌잡이개발자 2023. 3. 20. 02:15

리액트에서 state는 떼려야 뗄 수 없는 것으로 state의 상태 관리를 위한 다양한 라이브러리가 존재합니다. 지난번 Client-side에서는 프로젝트의 클라이언트의 복잡도가 높지 않고, 공통으로 사용하는 전역 상태의 데이터도 많지 않아 리액트의 context를 통해 로그인한 유저의 데이터를 저장했습니다. 그렇다면 Server-side에서 가져오는 데이터를 위한 상태 관리도 필요할 텐데요. 오늘은 제 프로젝트에서 Server-side에서 state 상태 관리를 위해 도입한 React-Query에 대해 알아보고 활용한 방법에 대해 적어보겠습니다. 

 


 

Server State를 관리하며 발생할 수 있는 문제

원격 데이터는 서버에서 관리되는 데이터를 말합니다. 데이터를 가져오고 업데이트하기 위해서 비동기 API가 필요합니다. 그런데 해당 데이터가 클라이언트가 모르게 원격에서 변경되면 응답은 구식(out-of-date)이 될 수 있습니다. 

 

React-Query란

서버의 값을 클라이언트에 가져오거나 캐싱, 업데이트, 에러핸들링 등 비동기 로직을 지원하는 data fetching 라이브러리입니다. 

 

React-Query가 제공하는 다음과 같은 기능을 통해 Server State를 더욱 효율적으로 관리할 수 있습니다.

  • 데이터 캐싱
  • 데이터를 캐시에서 유지할 시간
  • 리프레시 간격
  • 서버 데이터 중복 호출 제거
  • 페이지네이션, 레이지 로딩 데이터의 성능 최적화
  • 쿼리 결과에 대한 성공, 로딩, 에러 콜백

 

React-Query의 라이프 사이클

fetching: 요청 중인 데이터

fresh: 신선한 데이터(↔ stale한 데이터). 컴포넌트가 마운트, 업데이트되어도 데이터를 다시 요청하지 않습니다.

stale: 만료된 데이터. 컴포넌트가 마운트, 업데이트 되면 데이터를 다시 요청합니다.

inactive: 사용하지 않는 데이터로 일정 시간이 지나면 가비지 컬렉터가 캐시에서 제거합니다.

delete: 가비지 컬렉터에 의해 캐시에서 제거된 상태를 말합니다.

 

 

➡️ 기본적으로 데이터를 fetching 해온 후 데이터를 캐싱하며 백그라운드에서 서버에 주기적으로 polling을 하여 데이터가 유효한지 검사하고 유효하지 않으면(stale) 업데이트해 데이터를 동기화합니다.

 

React-Query 사용하기

react-query 설치하기

npm i react-query

 

QueryClientProvider

React Query는 캐시를 관리하기 위해 QueryClient 인스턴스를 사용합니다. 그리고 QueryClientProvider로 최상단에서 감싸줍니다.

React Query DevTools는 쿼리 상태를 이해하는 데 큰 도움을 줍니다. 또한 현재 캐시에 있는 데이터를 알려주기 때문에 디버깅을 쉽게 할 수 있습니다.

import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import App from './App';
import { QueryClient, QueryClientProvider } from 'react-query';
import { UserProvider } from './context/UserContext';
import { ReactQueryDevtools } from 'react-query/devtools';

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      // 실패 시 retry하는 횟수 (default: 3)
      retry: 1,
      // 윈도우 창이 포커스 될 때마다 refetch (default: true)
      refetchOnWindowFocus: false,
    },
  },
});

root.render(
  <QueryClientProvider client={queryClient}>
    // 데이터의 상태를 확인할 수 있는 개발자 도구
    <ReactQueryDevtools initialIsOpen={true} />
    <BrowserRouter>
      <UserProvider>
        <App />
      </UserProvider>
    </BrowserRouter>
  </QueryClientProvider>
);

 

React Query는 API 요청이 Query와 Mutation으로 나누어져 있습니다.

 

useQuery

서버에서 데이터를 가져올 때 사용하는 요청입니다.

  • 첫 번째 인자로 Unique Key를 받습니다. 해당 Key를 통해 다른 곳에서도 데이터를 꺼내올 수 있습니다.
// FeedDetail.tsx

import { useQuery } from 'react-query';
import { getFeed } from '../services/feed';
 
const { isLoading, isError, data, error } = useQuery(
  ['getFeed', _id], // queryKey: 데이터를 캐시할 때 사용하는 Unique Key
  () => getFeed({ _id }) // fetchFn: Promise를 반환하는 함수
);

if (isLoading) {
  return <Loading />;
}

if (isError && isAxiosError(error)) {
  return <NotFound />;
}

if (!isLoading && !data?.data) {
  return <NotFound />;
}

// ...

 

useMutation

서버의 데이터 변경(생성, 수정, 삭제)을 요청할 때 사용합니다.

// FeedDetail.tsx

import { toggleLikeFeed } from '../services/feed';

const queryClient = useQueryClient();
 
const { mutate: likeFeedMutation } = useMutation(
  // mutation 요청을 수행하기 위한 Promise를 반환하는 함수
  toggleLikeFeed, {
    // 성공 시 실행
    onSuccess: () => {
      // Mutation이 성공하면 쿼리를 refetch 함
      queryClient.invalidateQueries(['getFeed', _id]);
    },
    // 에러 발생 시 실행
    onError: (error: TError) => {
      if (error.response.status === 401) {
        alert('로그인 후 이용해주세요.');
      }
    setIsLiked((prev) => !prev);
  },
});

 

React Query에는 이 밖에도 많은 옵션과 다양한 기능들이 있습니다. React Query 공식 홈페이지에서 필요한 상황에 따라 알맞은 기능을 찾아보고 적용하는 것이 좋을 것 같습니다. 참고로 React Query의 useInfiniteQuery는 무한 스크롤을 간편하게 만들 수 있는 기능이며 다음 포스팅에서 다루겠습니다!  

 

 

🧗‍♀️ 제가 진행한 프로젝트가 궁금하다면

🔽 프론트엔드는 이곳에서 확인하실 수 있습니다.

https://github.com/Team-Madstone/doljabee-fe

 

GitHub - Team-Madstone/doljabee-fe: Climbing Community

Climbing Community. Contribute to Team-Madstone/doljabee-fe development by creating an account on GitHub.

github.com

 

🔽 백엔드는 이곳에서 확인하실 수 있습니다.

https://github.com/Team-Madstone/doljabee-be

 

GitHub - Team-Madstone/doljabee-be: Climbing Community

Climbing Community. Contribute to Team-Madstone/doljabee-be development by creating an account on GitHub.

github.com

 

 

참고 자료

https://tanstack.com/query/v3/

https://tech.kakaopay.com/post/react-query-1/

https://www.youtube.com/watch?v=MArE6Hy371c&t=2195s

반응형