Tanstack Query는 과거에 react-query라는 이름으로 알려져있었다.
업데이트가 되면서 리액트 외에도 Vue, Svelet, Angular 등을 지원하게 되면서 이름이 변경되었다.
React Query는 서버의 데이터를 가져와 캐싱
해주는 것에 최적화 되어 있어 사용된다.
# npm
npm i @tanstack/react-query
# or yarn
yarn add @tanstack/react-query
추가적으로 DevTool을 설치해준다.
# npm
npm i -D @tanstack/react-query-devtools
# or yarn
yarn add -D @tanstack/react-query-devtools
우선, 다음과 같이QueryClientProvider
와 ReactQueryDevtools
를 사용한 컴포넌트를 생성해준다.
이렇게 Provider를 생성해주어야 이 Provider로 감싼 컴포넌트끼리 데이터를 공유할 수 있다.
import React, { useState } from "react";
import { QueryClientProvider, QueryClient } from "@tanstack/react-query";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
type Props = {
children: React.ReactNode;
};
function RQProvider({ children }: Props) {
const [client] = useState(
new QueryClient({
defaultOptions: {
// react-query 전역 설정
queries: {
refetchOnWindowFocus: false,
retryOnMount: true,
refetchOnReconnect: false,
retry: false,
},
},
})
);
return (
<QueryClientProvider client={client}>
{children}
<ReactQueryDevtools initialIsOpen={process.env.NEXT_PUBLIC_MODE === "local"} />
// initailIsOpen이 True면 devtool을 활성화해준다.
</QueryClientProvider>
);
}
export default RQProvider;
v4에서는 Hydrate
컴포넌트였지만 v5에서는 HydrationBoundary
로 명칭이 바뀌었다.
서버 컴포넌트에 다음과 같이 작성해준다.
import { HydrationBoundary, QueryClient, dehydrate } from "@tanstack/react-query";
export default async function Home() {
const queryClient = new QueryClient();
await queryClient.prefetchQuery({ queryKey: ["posts", "recommends"], queryFn: getPostRecommends });
const dehydratedState = dehydrate(queryClient); // 서버사이드 렌더링을 위한 dehydrate
return (
<main>
<HydrationBoundary state={dehydratedState}>
<PostRecommends />
</HydrationBoundary>
</main>
);
}
위 코드는 다음과 같은 방식으로 동작한다.
prefetchQuery
를 사용하여 데이터를 서버에서 미리 패칭한다. dehydrate
함수를 통해 직렬화되어 props로 전달된다.QueryClientProvider
와 HydrationBoundary
컴포넌트를 통해 초기 상태로 사용된다. 이렇게 하면 클라이언트가 첫 번째 렌더링 시 이미 서버에서 패칭된 데이터를 사용하게 되어, 추가적인 데이터 패칭 요청 없이 빠르게 렌더링할 수 있다.클라이언트 측에서는 useQuery 훅을 사용하여 데이터에 접근한다. React Query는 이미 서버에서 패칭된 데이터를 사용하므로, 클라이언트에서 다시 데이터를 패칭하지 않아도 된다. 필요 시 클라이언트 측에서 데이터를 갱신할 수 있다
useQuery를 통해 데이터를 패칭할 수 있다.
react query는 query keys를 기반으로 해서 쿼리 캐싱을 관리하므로
queryKey는 유니크한 값으로 작성해주어야 한다.
queryFn에는 데이터 패칭을 위한 함수를 작성해주면 된다.
import { useQuery } from "@tanstack/react-query";
export default function PostRecommends() {
const { data } = useQuery({ queryKey: ["posts", "recommend"], queryFn: getPostRecommends });
return data?.map((post) => <Post key={post.postId} post={post} />);
}
React Query Devtools를 설치하면 다음과 같은 상태를 확인할 수 있다.
기본적으로 서버에서 데이터를 불러오면 Fresh 상태이다.
Fresh
는 서버로부터 불러온 데이터가 최신 데이터임을 의미한다.
이는 개발자가 직접 설정할 수 있다.
리액트쿼리는 기본적으로 데이터가 Fresh가 아니라고 기본값으로 설정되어 있다.
Fresh 상태의 지속시간을 설정해주고 싶으면 staleTime
을 재설정하면 된다.
기본값은 0으로 되어있고 ms단위로 작성한다.
const { data: post, error } = useQuery<IPost, Object, IPost, [_1: string, _2: string]>({
queryKey: ["posts", id],
queryFn: getSinglePost,
staleTime: 60 * 1000, // 1분뒤 Stale 상태로 변경된다.
gcTime: 300 * 1000,
});
Stale
은 기회가 되면 서버에서 데이터를 가져오라는 의미이다.
여기서 기회란, 보통 3가지 설정에 따라 데이터를 가져온다.
useQuery에서 따로 설정을 해줄 수 있으며, 다음과 같이 전역설정을 해주어도 된다.
const [client] = useState(
new QueryClient({
defaultOptions: {
// react-query 전역 설정
queries: {
refetchOnWindowFocus: false, // 탭전환시
retryOnMount: true, // 컴포넌트가 Unmount/Mount시
refetchOnReconnect: false, // 인터넷 연결시
retry: false,
},
},
})
);
refetchOnWindowFocus
: 다른 탭으로 이동했다가 다시 돌아오는 경우 데이터를 새로 가져온다retryOnMount
: 컴포넌트가 Unmount되었다가 Mount될 때 데이터를 새로 가져온다.refetchOnReconnect
: 인터넷 연결이 끊겼다가 다시 연결이 된 경우 데이터를 새로 가져온다.데이터가 Inactive
는 데이터를 현재 페이지에서 사용하고 있는지 여부를 확인할 수 있다.
Inactive
상태가 되면 기본적으로 gcTime(garbage collection)이 시작된다. gcTime에 설정된 시간이 지나고나면 메모리에서 제거된다.
const { data: post, error } = useQuery<IPost, Object, IPost, [_1: string, _2: string]>({
queryKey: ["posts", id],
queryFn: getSinglePost,
staleTime: 60 * 1000,
gcTime: 300 * 1000, // 5분, 기본값
});
주의해야할 점
staleTime
(캐시 타임을 얼마나 오랫동안 가지고 있을지)은gcTime
(캐시를 언제 지울지)보다 짧아야한다.
리액트 쿼리 기능중에 데이터를 가져오는 것을 멈추게하는 기능이 있는데, 그상태를 나타낸다.
데이터를 가져오는 순간적인 상황
Refetch
: 데이터를 무조건 새로 가져온다.Invalidate
: Refetch와 유사하나, Refetch와 달리 어떤 데이터의 Query Details의 Observers
가 0일 때, Invalidate를 누르면 해당 데이터를 가져오는 로직이 실행될 때, 그 순간에 데이터를 가져온다.Reset
: useQuery에 initailData
가 있는 경우 해당 데이터로 Reset된다. 정의가 되어 있지 않으면 데이터를 새로 가져온다.Remove
: 데이터를 제거한다.Trigger Loading/Restore Loading
: 로딩 상태를 확인하고자 할 때 사용한다.Trigger Error/Restore Error
: 에러 상태를 확인하고자 할 때 사용한다.참고
Next + React Query로 SNS 서비스 만들기
Overview | Tanstack Query React Docs