Post

React-Query 적용하기

React-Query란?

리액트 애플리케이션에 데이터를 불러오고 캐싱하며, 서버 데이터와의 동기화 및 업데이트 하는 작업을
개발자가 쉽고 간단하게 할 수 있도록 도와주는 라이브러리이다.




사용 목적

서버로부터 받아오는 데이터를 관리하기 위해 서버 상태 관리를 위한 라이브러리를 찾아보았다.

검색 결과 대부분 redux에서 swr이나 react-query로 바꿔가거나 같이 사용하는 추세임을 확인하였다.

swr과 react-query의 차이점을 파악해 보았고 프로젝트에 적합한 react-query를 사용하기로 하였다.

SWR과 React-Query의 차이에 대한 내용은 SWR과 React-Query 비교하기 게시글을 통해 확인할 수 있습니다.




사용 방법

1. 설치

1
 $ npm install @tanstack/react-query @tanstack/react-query-devtools


2. 적용하기

1
2
3
4
5
6
7
8
9
10
11
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";

const queryClient = new QueryClient();

function App({ Component, pageProps }) {
  return (
    <QueryClientProvider client={queryClient}>
      <Component {...pageProps} />
    </QueryClientProvider>
  );
}


3. React-Query SSR에 적용하기

  • React-Query로 SSR을 적용하는 방법InitialData 속성 사용, Hydration 두가지가 존재한다.

    방법 1. InitialData

    SSR 메서드로 불러온 응답을 React Query 기본값으로 넣어주는 방법

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    export async function getStaticProps() {
      const posts = await getPosts();
      return { props: { posts } };
    }
    
    function Posts(props) {
      const { data } = useQuery({
        queryKey: ["posts"],
        queryFn: getPosts,
        initialData: props.posts
      });
    
      // ...
    }
    
    • initialData로 데이터를 명시해주면 되기 때문에 구현을 간단하지만 여러 컴포넌트에서 데이터를 사용한다면 props계속 내려줘야하기 때문에 비효율적이다.

    방법 2. Hydration

    SSR 내에서 prefetch를 통해 쿼리를 불러온 뒤, queryClient에서 dehydrate한 상태값으로 페이지에 전달

    hydrate에 대한 내용은 hydrate 알아보기 게시글을 통해 확인할 수 있습니다.

    _app.jsx

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    
    import {
      Hydrate,
      QueryClient,
      QueryClientProvider
    } from "@tanstack/react-query";
    
    const queryClient = new QueryClient();
    
    function App({ Component, pageProps }) {
      return (
        <QueryClientProvider client={queryClient}>
          <Hydrate state={pageProps.dehydratedState}>
            <Component {...pageProps} />
          </Hydrate>
        </QueryClientProvider>
      );
    }
    

    // 페이지 SSR

    1
    2
    3
    4
    5
    6
    7
    
    export async function getServerSideProps() {
      const queryClient = new QueryClient();
      await queryClient.prefetchQuery(["schedules "], () =>
        getSchedule(user.email)
      );
      return { dehydratedProps: dehydrate(queryClient) };
    }
    
    • 모든 컴포넌트에서 schedule 데이터 요청할 때, schedules의 key로 가져올 수 있음.
    1
    2
    3
    
    const { data: schedule } = useQuery(["schedules"], () =>
      getSchedule(useremail)
    );
    


4. 데이터 Get - useQuery

1
2
import { useQuery } from "react-query";
const { data, isLoading, error } = useQuery(queryKey, queryFn, options);
  • QueryKey

    • QueryKey 를 기반으로 데이터 캐싱을 관리한다.

    • 문자열 또는 배열로 지정할 수 있다.

    • 쿼리가 변수에 의존하는 경우에는 QueryKey 에도 해당 변수를 추가해주어야한다.

    1
    2
    3
    
    const { data, isLoading, error } = useQuery(["todos", id], () =>
      axios.get(`http://.../${id}`)
    );
    


  • Query Functions

    • useQuery 의 두번째 인자에는 promise 를 반환하는 함수



5. 데이터 Post - useMutate

1
2
3
4
5
6
7
8
9
10
11
12
import { useMutation } from "react-query";

const { mutate } = useMutation(mutationFn, {
  onSuccess: () => {
    // mutate가 정상적으로 실행되면, 함수를 실행합니다.
    console.log("success");
  },
  onError: () => {
    // mutate가 실패하면, 함수를 실행합니다.
    console.log("error");
  }
});


  • Mutation Functions

    • 어떻게 동작할지 정의만 하고, mutate 함수를 통해 나중에 실행된다.


  • queryClient.invalidQueries

    • 전달받은 queryKey의 Query를 invalid 처리하고, 해당 Query가 active할 경우 다시 refetch

    • 특정 API 호출 후, 데이터를 갱신하고 싶을 때 사용할 수 있습니다

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
      const POST_KEY = ["post"];
    
      const { data: post1 } = useQuery(POST_KEY, () => getPost(1).then((res) => res));
    
      const { mutate } = useMutation((post: Post) => update(post), {
      onSuccess: () => queryClient.invalidQueries(POST_KEY);
      });
    
      const queryClient = useQueryClient();
    
      mutate({
      id: 1,
      userId: 2,
      title: 'title from 2',
      body: 'body from 2',
      });
    
This post is licensed under CC BY 4.0 by the author.