개발자
류준열
prefetchQuery 이용해서 로딩제거
테이블 컴포넌트의 로딩에 대해 고민하다가 한 작업이다.
Table 데이터를 첫 렌더링때는 서버컴포넌트에서 받은 데이터를 보여주고, 그 이후 인터렉션이 발생하면 클라이언트에서 fetch를 할 수 있지 않을까? 라는 생각을 했다.
두가지가 맘에 걸렸다.
- 페이지를 넘겼을때 서버 컴포넌트에서 받아온 데이터를 어떻게 클라이언트 사이드 데이터로 교체 할 것인가
- next 서버에서 데이터를 받아올때 revalidateTime은 어떻게 설정해야 하는가
고민하던 중 tanstack query의 advanced serverside rendering을 보고 해답을 찾았다.
서버 컴포넌트에서 prefetchQuery를 사용해 데이터를 미리 캐싱한 후, HydrationBoundary를 활용해 클라이언트에서 즉시 데이터를 사용할 수 있도록 했다.
서버 컴포넌트에서 데이터 캐싱하기
import { dehydrate, QueryClient } from '@tanstack/react-query';
import { getDevices } from '@/api/devices';
export default async function Page() {
const queryClient = getQueryClient();
// ['devices',1,'']에 getDevices의 데이터가 캐싱된다.
// await 걸면 렌더링전에 기다려서 HTML 내려주기까지 시간 더 쓴다.
// 나는 1초 미만이라 그냥 await 걸었다.
await queryClient.prefetchQuery({
queryKey: ['devices',1,''],
queryFn: getDevices,
});
return (
<HydrationBoundary state={dehydrate(queryClient)}>
{children}
</HydrationBoundary>
);
}
SSR에서 api 대기 시간 관리
여기서 아래와 같이 Suspense를 이용하면 prefetch는 하지만 로딩이 걸린다.
import { dehydrate, QueryClient } from '@tanstack/react-query';
import { getDevices } from '@/api/devices';
export default async function Page() {
const queryClient = getQueryClient();
// ['devices',1,'']에 getDevices의 데이터가 캐싱된다.
// await 제거
queryClient.prefetchQuery({
queryKey: ['devices',1,''],
queryFn: getDevices,
});
return (
<HydrationBoundary state={dehydrate(queryClient)}>
<Suspense fallback={<div>로딩</div>}>
{children}
</Suspense>
</HydrationBoundary>
);
}
나는 1초 미만의 api 요청에 로딩을 보여주는게 더 지저분하다고 생각해서 그냥 await 걸고 기다리게 했다.
어쨌든 서버컴포넌트에서 prefetchQuery를 하게 되면 렌더링전에 데이터를 받아서 캐싱하므로, 클라이언트에서는 거의 즉시 렌더링이라고 봐도 된다.