React Query 与 SSR 整合实践 Integrating React Query with Server-Side Rendering (SSR)

📌背景 / Background

为了提升 React 应用的首屏性能,我们采用 SSR(服务端渲染)进行初始 HTML 输出;同时希望使用 React Query 管理异步数据缓存。但两者默认工作方式并不一致,需要特别设计协调机制。

To improve first-screen performance in a React app, we use Server-Side Rendering (SSR) for the initial HTML output, while also leveraging React Query to manage async data and caching. Since their workflows differ, a proper integration strategy is necessary.

🧩 技术目标 / Goals

利用 React Router 的 loader() 实现 SSR 数据预取
Use React Router’s loader() to preload data on the server.

使用 React Query 管理客户端缓存、状态与交互
Use React Query for client-side caching and data state.

服务端注入数据 → 客户端复用而不重复拉取
Inject data via SSR and reuse it on the client without refetching.

⚙️ SSR 整合代码 / SSR Integration Code

// 1. 服务端渲染阶段
const queryClient = new QueryClient()

const AppRouterStr = renderToString(
            <Provider store={store}>
                <QueryClientProvider client={queryClient}>
                    <StaticRouterProvider router={router} context={context} />
                </QueryClientProvider>
            </Provider>
        );

SSR服务器注入数据我们架构使用React router的loader机制:

{
                path: 'movies',
                loader:
                    async () => {
                        const data = await getMovies(); // 发给本地 Express 转发
                        return json(data);
                    },
                element: <Movies />,

            }
// 2. 客户端页面组件
const loaderData = useLoaderData()

const { data } = useQuery({
  queryKey: ['MOVIES', page],
  queryFn: () => getMovies(page),
  initialData: page === 1 ? loaderData : undefined,
  keepPreviousData: true
})

loaderData数据通过initialData传入useQuery

我们不需要useState来通过改变page刷新页面,queryKey中依赖的变量只要变了,就会重新渲染界面。

当然,客户端入口也需要queryClient的包裹

hydrateRoot(document.getElementById('root'),
    <Provider store={clientStore} serverState={preloadedState}>
        <QueryClientProvider client={queryClient}>
            <RouterProvider router={router} />
        </QueryClientProvider>
    </Provider>);

✅ 总结 / Summary

组成作用 / Role
loader() SSR 时预取数据 Preload data on server
useLoaderData() 提供服务端注入的数据 Use server-passed data
useQuery() 管理缓存与客户端状态 Manage client-side cache/state
initialData 避免客户端重复请求 Avoid client-side refetch
QueryClientProvider 统一注入上下文 Context for hydration

 

posted @ 2025-06-06 01:59  PEAR2020  阅读(40)  评论(0)    收藏  举报