Next.jsのSSRで取得した値をTanStackQueryの仕組みで更新する
Next.js
TanStackQuery
ReactQuery
フロントエンド
知識
運用
app/layout.tsなどのSSRコンポーネントで、prefetchQueryを行い、dehydrateをproviderに渡す。
ts
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を登録する。
ts
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を行い再取得する。
ts
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],
});
},
});
};