const prefetchTodos = async () => {
// The results of this query will be cached like a normal query
await queryClient.prefetchQuery('todos', fetchTodos)
}
useQuery('todos', fetchTodos)
이게 마운트 되면todos
와 fetchTodos
를 키로 데이터는 캐싱된다.staleTime
이 지난 뒤에는 hook
이 이걸 stale
이라고 표시한다.useQuery('todos', fetchTodos)
이게 마운트 되면 이미 캐싱된 데이터가 있으므로 캐시에서 데이터를 받아서 응답을 준다.initialData
형태로 넘겨주는 것initialData
를 사용하는 방법
- getStaticProps
나 getServerSideProps
를 써서 useQuery
의 initalData
옵션으로 데이터를 전달해 줄 수 있다.
- getServerSideProps
이름으로 된 함수를 page
디렉토리에서 export
하면 nextjs
는 매 요청마다 여기서 요청한 데이터를 prop
로 넘겨주며 페이지를 새로 pre-render
한다.
- getStaticProps
이름으로 된 함수를 page
디렉토리에서 export
하면 nextjs
는 빌드 타임에 여기서 반환된 데이터를 prop
으로 넘겨주며 페이지를 pre-render
한다.
// getStaticProps를 쓰는 방법
export async function getStaticProps() {
const posts = await getPosts()
return { props: { posts } }
}
function Posts(props) {
const { data } = useQuery('posts', getPosts, { initialData: props.posts })
// ...
}
Hydration
을 사용하는 방법
- 리액트 쿼리는 nextjs에서라면 서버에서 미리 여러개의 쿼리를 prefetching하는 기능을 제공한다. 그리고 그러한 쿼리들을 queryClient에서 dehydrating할 수 있게 한다. 이건 서버에서 즉시 사용가능한 페이지를 prerendering 할 수 있다는 것을 의미한다. 리액트 쿼리는 이후 완전한 기능을 가진 쿼리로 hydrate할 수 있게 한다. 만약 클라이언트에서 해당 데이터가 stale되어 있다고 느끼면 다시 refetching도 할 수 있다.
- 이렇게 서버에서 쿼리를 캐싱하고 hydration 기능을 제공하려면
1. queryClient 인스턴스를 네 app에서 생성해야 한다.
2. 이 말은 응답 결과가 다른 유저나 다른 요청들과 공유되지 않는다는 것을 의미한다.
3. 그리고 컴포넌트의 lifecycle에서 client가 한번만 생성되게 할 수 있다.
4. 그리고 네 app을 로 감싼 후 client instance를 전달해라.
5. 그 다음 네 app을 로 감싸고 pageProps로 dehydratedState
를 전달해라.
// _app.jsx
import { Hydrate, QueryClient, QueryClientProvider } from 'react-query'
export default function MyApp({ Component, pageProps }) {
const [queryClient] = React.useState(() => new QueryClient())
return (
<QueryClientProvider client={queryClient}>
<Hydrate state={pageProps.dehydratedState}>
<Component {...pageProps} />
</Hydrate>
</QueryClientProvider>
)
}
그리고 원하는 페이지에서 QueryClient를 새로 만들어라.
이는 데이터를 다른 유저나 요청이 공유하지 않게 하기 위함이다.
그리고 client의 prefetchQuery
메서드를 이용해서 prefetch해라
그리고 Dehydrate를 이용해 캐시 데이터를 지우고 DehydratedState props를 전달해라.
// pages/posts.jsx
import { dehydrate, QueryClient, useQuery } from 'react-query';
export async function getStaticProps() {
const queryClient = new QueryClient()
await queryClient.prefetchQuery('posts', getPosts)
return {
props: {
dehydratedState: dehydrate(queryClient),
},
}
}
function Posts() {
// This useQuery could just as well happen in some deeper child to
// the "Posts"-page, data will be available immediately either way
const { data } = useQuery('posts', getPosts)
// This query was not prefetched on the server and will not start
// fetching until on the client, both patterns are fine to mix
const { data: otherData } = useQuery('posts-2', getPosts)
// ...
}