サーバーサイドレンダリング
Next.jsでのサーバーサイドレンダリング
RTK Queryは、Next.jsを使用したサーバーサイドレンダリング(SSR)を、リハイドレーションとnext-redux-wrapperの組み合わせでサポートしています。
ワークフローは以下の通りです
next-redux-wrapper
を設定しますgetStaticProps
またはgetServerSideProps
内でinitiate
アクションを使用して、すべてのクエリをプリフェッチします。例:store.dispatch(api.endpoints.getPokemonByName.initiate(name))
await Promise.all(dispatch(api.util.getRunningQueriesThunk()))
を使用して、各クエリが完了するのを待ちます
createApi
呼び出しで、extractRehydrationInfo
オプションを使用してリハイドレーションを設定します- TypeScript
- JavaScript
next-redux-wrapperリハイドレーションの例import type { Action, PayloadAction } from '@reduxjs/toolkit'
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
import { HYDRATE } from 'next-redux-wrapper'
type RootState = any // normally inferred from state
function isHydrateAction(action: Action): action is PayloadAction<RootState> {
return action.type === HYDRATE
}
export const api = createApi({
baseQuery: fetchBaseQuery({ baseUrl: '/' }),
extractRehydrationInfo(action, { reducerPath }): any {
if (isHydrateAction(action)) {
return action.payload[reducerPath]
}
},
endpoints: (build) => ({
// omitted
}),
})next-redux-wrapperリハイドレーションの例import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
import { HYDRATE } from 'next-redux-wrapper'
function isHydrateAction(action) {
return action.type === HYDRATE
}
export const api = createApi({
baseQuery: fetchBaseQuery({ baseUrl: '/' }),
extractRehydrationInfo(action, { reducerPath }) {
if (isHydrateAction(action)) {
return action.payload[reducerPath]
}
},
endpoints: (build) => ({
// omitted
}),
})
next.js
を使用した例のリポジトリはこちらで入手できます。
メモリリークは想定されていませんが、レンダリングがクライアントに送信され、ストアがメモリから削除される際に、store.dispatch(api.util.resetApiState())
を呼び出して、不正なタイマーが実行されたままにならないようにすることもできます。
静的サイト生成(SSG)で古いデータを提供しないようにするには、refetchOnMountOrArgChange
を、ページが生成されてからそれほど時間が経過していない場合にデータが再フェッチされるように、900(秒)などの適切な値に設定するとよいでしょう。
他の場所でのサーバーサイドレンダリング
next.js
を使用しておらず、上記の例をSSRフレームワークに適合させることができない場合、エフェクト内で安全にではなく、レンダリング中に非同期コードを実行する必要があるSSRシナリオをサポートするために、unstable__
マーク付きのアプローチが利用可能です。これは、getDataFromTree
をApolloで使用するのと同様のアプローチです。
ワークフローは以下の通りです
レンダリング中に非同期処理を実行する
createApi
のバージョンを作成します- TypeScript
- JavaScript
import {
buildCreateApi,
coreModule,
reactHooksModule,
} from '@reduxjs/toolkit/query/react'
const createApi = buildCreateApi(
coreModule(),
reactHooksModule({ unstable__sideEffectsInRender: true })
)import {
buildCreateApi,
coreModule,
reactHooksModule,
} from '@reduxjs/toolkit/query/react'
const createApi = buildCreateApi(
coreModule(),
reactHooksModule({ unstable__sideEffectsInRender: true })
)const api = createApi({...})
を呼び出すときに、カスタムのcreateApi
を使用します次のレンダリングサイクルを実行する前に、
await Promise.all(dispatch(api.util.getRunningQueriesThunk()))
を使用して、すべてのクエリが完了するのを待ちます