NextJS中getServerSideProps与react-query预取数据及数据丢失问题解决
问题分析与解决方案
核心问题原因
- 缺少全局React Query Provider:未在
_app.tsx中配置全局的QueryClientProvider,导致每次页面跳转都会创建全新的QueryClient实例,之前的缓存数据被清空,DevTools中自然看不到历史数据。 - 查询键与数据类型不一致:分页参数可能为字符串类型,导致查询键(如
['notices', '2'])与预期的数字键(['notices', 2])不匹配,缓存无法正确关联。
解决步骤
1. 配置全局React Query Provider
在pages/_app.tsx中添加全局QueryClient实例,确保整个应用共享同一缓存:
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; import type { AppProps } from 'next/app'; // 创建全局QueryClient实例 const queryClient = new QueryClient({ defaultOptions: { queries: { staleTime: 30 * 1000, // 按需设置,减少重复请求 retry: 1, }, }, }); export default function MyApp({ Component, pageProps }: AppProps) { return ( <QueryClientProvider client={queryClient}> <Component {...pageProps} /> <ReactQueryDevtools initialIsOpen={false} /> </QueryClientProvider> ); }
2. 优化公告页面代码
调整getServerSideProps和useQuery逻辑,确保查询键一致、缓存正确存入,并实现预取:
// page/notice/index.tsx export async function getServerSideProps(context) { // 处理page为空的情况,默认设为1,同时转为数字类型 const currentPage = Number(context.query.page) || 1; const res = await getNotices(currentPage); const data = res.data; return { props: { result: data, currentPage, // 明确传递数字类型的当前页 }, }; } export async function getNotices(page: number) { return await api.get(`/admin/notice?page=${page}`); } export default function Notice({ result, currentPage }) { const queryClient = useQueryClient(); const { data } = useQuery( ['notices', currentPage], // 数字类型的查询键,确保一致性 () => getNotices(currentPage), { initialData: result, // 将SSR获取的数据作为初始值存入缓存 select: (response) => response.data, // 匹配initialData的结构 staleTime: 30 * 1000, }, ); // 预取下一页数据(避免重复预取) useEffect(() => { const nextPage = currentPage + 1; // 先检查缓存是否已有数据,没有再发起预取 if (!queryClient.getQueryData(['notices', nextPage])) { queryClient.prefetchQuery( ['notices', nextPage], () => getNotices(nextPage), { staleTime: 30 * 1000 }, ); } // 可选:预取上一页数据 if (currentPage > 1 && !queryClient.getQueryData(['notices', currentPage - 1])) { queryClient.prefetchQuery( ['notices', currentPage - 1], () => getNotices(currentPage - 1), { staleTime: 30 * 1000 }, ); } }, [currentPage, queryClient]); // 你的渲染逻辑... }
3. 分页跳转优化(可选)
保持原有的router.push逻辑,确保传递数字类型的page参数:
// 分页按钮点击事件示例 const handlePageChange = (newPage: number) => { router.push(`/notice?page=${newPage}`); };
效果验证
完成上述配置后:
- 点击分页按钮时,
getServerSideProps会正常获取当前页数据,同时React Query会将该数据存入全局缓存。 - 预取的下一页数据会被缓存,用户点击下一页时可直接从缓存读取,提升体验。
- React Query DevTools中能看到所有已缓存的分页数据,不会再出现数据消失的情况。
内容的提问来源于stack exchange,提问作者emillly
相关产品推荐
相关产品推荐

