Next.jsのSSRで取得した値をTanStackQueryの仕組みで更新する
Next.js
TanStackQuery
ReactQuery
app/layout.tsなどのSSRコンポーネントで、prefetchQueryを行い、dehydrateをproviderに渡す。
export default async function RootLayout({
children,
}: {
children: React.ReactNode;
}): Promise<JSX.Element> {
let user: User | null = null;
let userCategories: UserCategory[] = [];
const accessToken = cookies().get('accessToken')?.value ?? '';
if (accessToken) {
const [userData, categoriesData] = await Promise.all([
getMe(accessToken),
getMeCategories(accessToken),
]);
user = userData;
userCategories = categoriesData;
}
const queryClient = new QueryClient();
await Promise.all([
queryClient.prefetchQuery({
queryKey: [GET_ME_KEY],
queryFn: async () => await Promise.resolve(user),
}),
queryClient.prefetchQuery({
queryKey: [GET_ME_CATEGORIES_KEY],
queryFn: async () => await Promise.resolve(userCategories),
}),
]);
return (
<html lang='ja'>
<body>
<Providers dehydratedState={dehydrate(queryClient)}>
{children}
</Providers>
</body>
</html>
);
}
HydrationBoundaryにdehydrateを登録する。
export const Providers = ({ dehydratedState, children, }: ProvidersProps): JSX.Element => { const [client] = useState( new QueryClient({ defaultOptions: { queries: { staleTime: 5000, retry: false, refetchOnWindowFocus: false, }, mutations: { retry: false, }, }, }) ); return ( <QueryClientProvider client={client}> <HydrationBoundary state={dehydratedState}> <RecoilRoot> <ToastContainer /> <Suspense fallback={<LinearLoading />}>{children}</Suspense> </RecoilRoot> </HydrationBoundary> </QueryClientProvider> ); };
更新したいタイミングでinvalidateQueriesを行い再取得する。
export const usePostMeMemo = (): UseMutationResult< boolean, fetch.FetchError, PostMeMemoRequest > => { const queryClient = useQueryClient(); return useMutation<boolean, fetch.FetchError, PostMeMemoRequest>({ mutationFn: postMeMemo, onSuccess: () => { void queryClient.invalidateQueries({ queryKey: [GET_ME_MEMOS_KEY], }); void queryClient.invalidateQueries({ queryKey: [GET_ME_CATEGORIES_KEY], }); }, }); };