React Query를 통해 서버 데이터를 pre-fetching할 수 있습니다. 이는 필요한 서버 데이터를 미리 fetching하고 캐싱하기때문에 서버 데이터를 요청하고 응답받는 시간을 줄일 수 있습니다.
pre-fetching한 쿼리 상태는 기본적으로 "stale 상태"를 갖고 있습니다. 해당 설정은 변경할 수 있습니다. 즉, pre-fetching된 데이터를 사용하고자 할 때 stale 상태이므로 re-fetching하게 됩니다. 이때 re-fetching하는 동안 기존 캐싱되어 있는 데이터를 사용하고 re-fetching이 완료된 이후 새롭게 re-fetching한 데이터로 교체하게 됩니다.
pre-fetching을 위한 메서드는 QueryClient
로 생성한 queryClient 객체가 제공합니다.
import { useQueryClient } '@tanstack/react-query'
function Component () {
const queryClient = useQueryClient()
// pre-fethcing,,,
queryClient.prefetchQuery(['key', ...deps], callbackFn, Options)
}
export default Component
queryClient의 prefetchQuery
메서드를 통해 pre-fetching할 수 있으며 이때 전달되는 인수는 useQuery
훅의 인수와 동일합니다.
isLoading
의 경우에는 캐싱된 데이터가 없고 데이터를 fetching 중인 경우 true
값을 갖습니다. 즉, 초기 데이터를 fetching 하거나 cacheTime이 만료되어 fetching하는 경우에만 isLoading
값이 true입니다.
isFetching
의 경우에는 fetching 중인 경우라면 언제나 true
값을 갖습니다.
만약 pre-fetching하여 데이터를 캐싱해둔 상태라면 isLoading
은 false
값을 갖지만 isFetching
의 경우에는 true
값을 갖습니다. 이는 pre-fetching된 데이터의 경우 상태가 stale이므로 re-fetching하기 때문에 isFetching
의 경우 true 값을 갖게 되고, isLoading
의 경우에는 데이터가 캐싱되어 있기 때문에 false
값을 갖게 됩니다.
useIsFetching
훅은 fethcing 중인 쿼리의 갯수를 정수로 반환하는 훅입니다. 즉, useIsFetcing
훅의 반환값이 0 이상인 경우에는 현재 fetching 중인 쿼리가 존재한다는 것을 의미합니다.
NextJS에서 SSR 기능을 사용할 때 서버에서 query를 pre-fetching하여 dehydrate하고, 클라이언트에서 이를 rehydrate할 수 있습니다.
클라이언트에서는 pre-fetch된 서버 데이터를 포함한 HTML 문서를 즉시 렌더링할 수 있으며, 해당 쿼리 정보를 포함한 queryClient까지 전달받아 사용할 수 있습니다.
// pages/_app.tsx
import { useState } from 'react'
import {
Hydrate,
QueryClient,
QueryClientProvider,
} from '@tanstack/react-query'
export default function App({ Component, pageProps }) {
const [queryClient] = useState(() => new QueryClient())
return (
<QueryClientProvider client={queryClient}>
<Hydrate state={pageProps.dehydratedState}>
<Component {...pageProps} />
</Hydrate>
</QueryClientProvider>
)
}
// pages/index.tsx
import {
NextPage,
QueryClient,
dehydrate
} from '@tanstack/react-query'
const PageComponent: NextPage = () => {
//,,,
}
export const getServerSideProps = () => {
const queryClient = new QueryClient()
await queryClient.prefetchQuery(['key'], callbackFn)
return {
props: {
dehydratedState: dehydrate(queryClient)
}
}
}
독립된 별도의 queryClient로 관리하게 된다면, 각 페이지나 컴포넌트마다 서로 영향을 주지 않으면서 데이터를 처리할 수 있게 되며, 데이터 요구사항이 격리되어 충돌을 방지할 수 있습니다.
<Hydrate>
컴포넌트의 경우 getServerSideProps
에서 생성된 queryClient(pageProps.dehydratedState
)를 전달받아 이를 state
에 작성하면 클라이언트측에 전달되고, 클라이언트측에서는 이를 사용합니다. 만약 dehydrate된 queryClient가 없다면 <QueryClientProvider>
의 client
에 작성된 queryClient를 사용하게 됩니다.
페이지 컴포넌트에서는 getServerSideProps
내에서 queryClient를 생성하고, pre-fetch한 뒤 반환값의 props 객체 내 dehydratedState 프로퍼티에서 dehydate
함수에 queryClient를 전달한 호출문을 작성합니다.