React Query는 prefetch를 지원합니다.
Next.js의 경우 다음과 같은 방식으로 SSR을 수행할 수 있습니다.
// pages/posts.jsx
import { dehydrate, QueryClient, useQuery } from '@tanstack/react-query'
import type { GetServerSideProps, NextPage } from 'next';
const Posts: NextPage = () => {
const { data } = useQuery(['posts'], getPosts)
// ...
}
export const getServerSideProps: GetServerSideProps = () => {
const queryClient = new QueryClient()
await queryClient.prefetchQuery(['posts'], getPosts)
return {
props: {
dehydratedState: dehydrate(queryClient),
},
}
}
export default Posts;
SSR을 적용하기 위해 다음과 같이 코드를 작성했습니다.
export const getServerSideProps: GetServerSideProps = async () => {
// ...
const queryClient = new QueryClient();
await queryClient.prefetchQuery([queryKeys.users, username], async () => {
await api.getProfileByUsername({ username });
});
return { props: { dehydratedState: dehydrate(queryClient) } };
};
그리고 다음과 같은 에러가 발생했습니다.
해당 에러에 대해 구글링 했을 때 useQuery
사용시 등록한 함수가 Promise
를 반환하지 않는 경우 이와 같은 에러가 발생할 수 있다는 내용을 찾았습니다.
하지만 저의 경우 prefetchQuery
에서 발생한 에러였고, prefetchQuery
에 등록한 함수가 Promise를 반환하고 있었습니다.
또한 모든 SSR에서 발생한 에러가 아니었기에 코드를 다른 SSR 코드와 비교하면서 천천히 확인해보았습니다.
그리고 정말 작은 차이점을 발견했습니다!
다음은 정상적으로 동작하는 코드입니다.
export const getServerSideProps: GetServerSideProps = async () => {
// ...
const queryClient = new QueryClient();
await queryClient.prefetchQuery(
[queryKeys.users, username],
async () => await api.getProfileByUsername({ username }),
return { props: { dehydratedState: dehydrate(queryClient), session } };
};
혹시 이 전의 문제가 있었던 코드와의 차이점을 찾으셨나요?
에러의 원인은 중괄호였습니다(또는 누락된 return 키워드).
에러가 발생했던 코드는 prefetchQuery
에 등록한 함수에 return
키워드 없이 중괄호가 사용되었습니다.
화살표 함수는 본문이 한 줄인 함수의 결과를 반환할 때 다음과 같이 작성할 수 있습니다.
const func = (...arge) => expression;
const func = (...arge) => {
return expression;
}
결과적으로 에러 발생의 원인은 화살표 함수를 잘못 사용하여 정상적으로 Promise
를 반환하지 못했기 때문이었습니다.
그래서 prefetchQuery
에 등록할 함수를 다음과 같이 작성하면 정상적으로 동작합니다.
// Error
async () => {
await api.getProfileByUsername({ username });
}
// OK
async () => await api.getProfileByUsername({ username })
// OK
async () => {
return await api.getProfileByUsername({ username });
}
참고
정말 좋은 글 감사합니다!