Next.js

NextJS에서 react-query 사용하기

Kir93 2022. 8. 15. 17:00
728x90
반응형

(해당 글은 next@12.2 react-query@3.39.1을 바탕으로 작성되었습니다.)

1. 왜 react-query인가?

이제 개발을 할 때 react-query는 필수에 가까운 요소가 됐다.

물론 NextJS를 사용하고 문서를 읽어본 사람들이라면 이런 의문을 가질 수 있다.

 

swr이 있는데?

 

물론 두 라이브러리 모두 좋은 라이브러리이다.

하지만 react-query를 사용해야 되는 이유를 간략하게 설명하겠다.

 

1. swr은 데이터 패칭(fetching)을 위한 리액트 훅이다.

이 말을 간단하게 이야기하자면 swr과 react-query는 get을 위한 useQuery는 존재한다.

그러나 post를 위한 useMutation은 react-query에만 존재한다.

물론 swr 역시 mutate가 있기는 하지만 react-query와 비교할 수는 없다.

 

2. Garbage Collection

react-query의 경우 Garbage collection이 존재하여 사용하지 않는 데이터의 경우 stale time(default 5분)이 지나면 자동으로 관리해 주지만 swr의 경우 개발자가 수동으로 관리해 주어야 되는 단점이 존재한다.

 

3. Request Cancellation

위와 비슷하게 swr에는 없고 react-query에만 존재하는 기능으로 api를 요청했을 때 반응이 없거나 만료될 경우 자동(수동으로도 가능)으로 취소해 주는 기능이다.

 

왜 react-query를 사용해야 되는지에 대해서는 swr과의 비교에서 이해할 수 있다.

내가 생각하기에 가장 큰 이유는 Caching이다.

 

Front내에서 최대한 부드러운 데이터 조작이 중요해진 요즘에 개발자가 수동으로 처리해야 될 데이터의 Caching을 자동으로 해준다는 메리트 만으로도 react-query를 사용하는데 전혀 부족함이 없다고 생각한다.

 

그럼 이제 NextJS에 react-query를 설정해 보도록 하겠다.

 

2. react-query Setting

가장 먼저 필요한 라이브러리들을 설치해준다.

npm install axios react-query

axios의 경우 JS의 기본 fetch를 사용해도 괜찮다.

 

이제 pages 폴더에 _app.tsx파일을 열어 아래와 같이 입력한다.

import React from 'react';
import Head from 'next/head';
import { AppProps } from 'next/app';
import { ReactQueryDevtools } from 'react-query/devtools';
import { QueryClient, QueryClientProvider } from 'react-query';

const client = new QueryClient({
  defaultOptions: {
    queries: {
      refetchOnWindowFocus: false,
    },
  },
});

const App: React.FC<AppProps> = ({ Component, pageProps }) => (
  <QueryClientProvider client={client}>
    {process.env.NODE_ENV !== 'production' ? <ReactQueryDevtools initialIsOpen={false} /> : null}
      <Head>
        <title>Next Template</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
      </Head>
        <Component {...pageProps} />
  </QueryClientProvider>
);

export default App;

위에부터 차근차근 설명하자면 react-query를 설정하는 방법은 무척 간단하다.

 

QueryClientProvider로 최상단을 감싸고 Provider에 QueryClient를 생성해 넣어주기만 하면 된다.

QueryClient에는 주로 공통적으로 사용할 옵션을 입력해 둘 수 있다.

나의 경우 window가 focus 됐을 경우 자동으로 refetch를 해주는 옵션 정도만 꺼 주었다.

이 외에도 많은 옵션이 있는데, 다른 옵션들은 react-query docs에서 확인하길 바란다.

 

그 아래로 ReactQueryDevtools가 있는데 react-query를 사용할 때 query와 mutation에 대한 정보를 제공한다.

나의 경우 production이 아닐 때만 ReactQueryDevtools를 불러오게 설정해 두었지만, 기본적으로 production 환경에서는 devtools가 포함되지 않기 때문에 나처럼 분기 처리를 할 필요는 없다.

 

3. useQuery 실제 사용법

이것으로 react-query를 사용할 준비가 모두 끝났다.

그럼 마지막으로 react-query를 사용하는 방법에 대해 설명하고 끝내겠다.

// 사용법 1
// apis/user.ts
...
export const useGetUser = async (userId: string, options: QueryOptions) => {
  const queryKey = `https://api.test.com/user`;
  const queryFn = await axios.get(`${queryKey}?userId=${userId}`).then((res) => res.data);
  return useQuery([queryKey, userId], queryFn, { ...options });
};

// useMutation 예시
export const usePutUser = async (data: IUser, options: QueryOptions) => {
  const queryKey = `https://api.test.com/user`;
  const queryFn = await axios.put(`${queryKey}?userId=${data.id}`, data).then((res) => res.data);
  return useMutation([queryKey, data.id], queryFn, { ...options });
};

// pages/index.tsx
...
const TIME = 1000 * 60 * 5; // 5m
const { data, loading } = useGetUser(1, {
  staleTime: TIME,
  cacheTime: TIME,
});
...

// 사용법 2
// pages/index.tsx
...
const TIME = 1000 * 60 * 5; // 5m
const userId = '1';
const queryKey = `https://api.test.com/user`;
const queryFn = () => axios.get(`${queryKey}?userId=${userId}`).then((res) => res.data);
const { data, loading } = useQuery([queryKey, userId], queryFn, {
  staleTime: TIME,
  cacheTime: TIME,
});
...

첫 번째 방식은 내가 불러오려는 API를 각각 만들어 두고 불러와서 사용하는 방식이고 두 번째 방식은 useQuery를 import해와 매번 다른 key를 넣어 제작하는 방식이다.

 

두 방식 중 어떤 방식을 사용해도 상관없지만 개인적으로는 첫 번째 방식을 선호하며 많은 분들이 첫 번째 방식으로 만드는 것으로 알고 있으니 참고하면 좋을 것 같다.

 

useMutation의 경우 위에서 예시와 공식 Docs를 참고하면 되며 useQuery와 사용법에 있어서 큰 차이가 나지 않기 때문에 더 이상의 설명은 생략하도록 하겠다.

 

 

반응형