Next.js + RTK Query:如何实现服务端渲染预取数据并支持数据更新?
解决RTK Query服务端预取静态HTML+客户端更新问题
核心思路
要实现服务端预取数据生成静态HTML,同时保留RTK Query的客户端更新能力,需要让服务端先获取数据并填充RTK Query缓存,再将缓存状态传递给客户端,客户端Hydrate时直接复用缓存,避免初始加载指示器。
代码修改步骤
1. 服务端页面预取数据并传递缓存状态
修改app/discussions/page.tsx,在服务端执行时预取数据,并用RTK Query的dehydrate序列化缓存,再通过Hydrate组件传递给客户端:
import { dehydrate, Hydrate } from '@reduxjs/toolkit/query/react'; // 导入你的RTK Query API实例(假设定义在services/discussionsApi.ts) import { api } from '../services/discussionsApi'; import { DiscussionList } from '../components/DiscussionList'; export default async function DiscussionListPage() { // 服务端预取数据,填充RTK Query缓存 await api.fetchDiscussions.initiate().unwrap(); // 序列化缓存状态,用于客户端Hydrate const dehydratedState = dehydrate(api); return ( <Hydrate state={dehydratedState}> <DiscussionList /> </Hydrate> ); }
2. 调整客户端组件逻辑
修改app/components/DiscussionList.tsx,去掉初始加载指示器的判断(因为服务端已预取数据,客户端Hydrate时直接从缓存读取),同时保留RTK Query的更新能力:
import { useFetchDiscussionsQuery } from '../services/discussionsApi'; // 假设你的讨论数据类型定义 type Discussion = { discussionId: string; title: string; body: string; }; export function DiscussionList() { const { data } = useFetchDiscussionsQuery(); // 仅保留极端情况的兜底(正常服务端预取后不会触发) if (!data) { return <p>Loading...</p>; } return ( <ul> {data.map((item: Discussion) => ( <li key={item.discussionId}> <h2>{item.title}</h2> <p>{item.body}</p> </li> ))} </ul> ); }
3. 确保RTK Query API实例配置正确
你的RTK Query API实例(比如services/discussionsApi.ts)需要是单例,确保服务端和客户端使用同一实例:
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; export const api = createApi({ reducerPath: 'discussionsApi', baseQuery: fetchBaseQuery({ baseUrl: '/api' }), endpoints: (builder) => ({ fetchDiscussions: builder.query({ query: () => '/discussions', // 可选:添加标签用于缓存更新 providesTags: ['Discussion'], }), // 其他更新/删除端点可以用invalidatesTags来触发缓存刷新 }), }); export const { useFetchDiscussionsQuery } = api;
关键说明
- 服务端预取:通过
api.fetchDiscussions.initiate().unwrap()在服务端触发查询,填充RTK Query缓存 - 缓存传递:
dehydrate将缓存序列化为可传递的状态,Hydrate组件让客户端RTK Query读取该缓存,避免重复请求 - 客户端更新:RTK Query仍会正常处理后续的数据更新(比如调用更新端点后,缓存会自动刷新,组件也会重新渲染)
内容的提问来源于stack exchange,提问作者Daniel Tonon
相关产品推荐
相关产品推荐

