Next.jsにTanStack Queryを入れたら、Google Mapの表示が爆速になりました!
テンションがあがったので手順をざっくりまとめます。
TanStack Query:非同期状態を効率よく管理できるライブラリ
Welcome to the Advanced Server Rendering...
Advanced Server Rendering | TanStack Que...
tanstack.com
ライブラリをインストールした後、Provider.tsxを作成します。
'use client';
import {
isServer,
QueryClient,
QueryClientProvider,
} from '@tanstack/react-query';
function makeQueryClient() {
return new QueryClient({
defaultOptions: {
queries: {
staleTime: 60 * 1000,
},
},
});
}
let browserQueryClient: QueryClient | undefined = undefined;
function getQueryClient() {
if (isServer) {
return makeQueryClient();
} else {
if (!browserQueryClient) browserQueryClient = makeQueryClient();
return browserQueryClient;
}
}
export default function Provider({ children }: { children: React.ReactNode }) {
const queryClient = getQueryClient();
return (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
);
}
上記のコンポーネントを、Layout.tsxの子要素をラップするように設置します。
これで、アプリケーション全体で QueryClient を使用できるようになります。
<Provider>{children}</Provider>Page.tsxで下記のようにデータをプリフェッチします。
import {
dehydrate,
HydrationBoundary,
QueryClient,
} from '@tanstack/react-query';
import GoogleMap from './components/GoogleMap';
import { fetchMarkers } from './marker';
export default async function StaticPage() {
const queryClient = new QueryClient();
await queryClient.prefetchQuery({
queryKey: ['fetchMarkers'],
queryFn: fetchMarkers,
staleTime: 5 * 60 * 1000,
});
const dehydratedState = dehydrate(queryClient);
return (
<div className="grid items-center justify-items-center min-h-screen">
<HydrationBoundary state={dehydratedState}>
<GoogleMap />
</HydrationBoundary>
</div>
);
}
クライアントコンポーネントでuseQueryを使って、プリフェッチしたデータにアクセスします。
'use client';
import React from 'react';
import { APIProvider, Map, AdvancedMarker } from '@vis.gl/react-google-maps';
import { useQuery } from '@tanstack/react-query';
import { useRouter } from 'next/navigation';
import { fetchMarkers } from '../marker';
import { Marker } from '@prisma/client';
const GoogleMap = () => {
const router = useRouter();
const {
data: markers,
isLoading,
isError,
error,
} = useQuery<Marker[], Error>({
queryKey: ['fetchMarkers'],
queryFn: fetchMarkers,
});これで、キャッシュを利用して効率よくデータを表示できるようになりました!
プリフェッチしたデータに対しCRUD処理を行うときは、キャッシュをクリアする処理を加えます。
クリアするのを忘れると、データを削除したのに画面の表示が変わらない・・・というバグが発生します。
キャッシュのクリアは、削除ボタンだとこんな感じです。
const deleteMarkerMutation = useMutation({
mutationFn: () => deleteMarker(id),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ['fetchMarkers'],
});
alert('施設をリストから削除しました');
router.push('/lists');
},
});invalidateQueriesのあたりで、'fetchMarkers'のQueryKeyがついたデータのキャッシュをクリアしています。
