Next.js Pages Router中tRPC服务端预取数据失效问题排查
问题:Next.js Pages Router中TRPC服务端预取数据后仍显示加载状态
我在Next.js Pages Router中通过服务端预取数据以避免加载状态,同时保留重取功能,使用getServerSideProps在服务端获取数据,generateSSGHelper函数完全参照文档实现(已确认未在其中用req & res生成上下文,不应在此处出错)。
服务端代码:
export const getServerSideProps = async (ctx: GetServerSidePropsContext<{ id: string }>) => { const helpers = generateSSGHelper() const id = ctx.params?.id if (typeof id !== 'string') throw new Error('no id') helpers.partner.getById.prefetch({ id }) return { props: { trpcState: helpers.dehydrate(), id, } } }
组件代码:
const SinglePartnerPage: NextPage<{ id : string }> = ({ id }) => { const partner = api.partner.getById.useQuery({ id }) // <= 服务端已预取 if (partner.status !== 'success') { // 此条件本不应成立 console.log('Loading!!') return <>Loading...</> } return ( ... ) }
实际情况是控制台打印了Loading!!,说明查询并未处于success状态,这给组件其他部分带来了问题。请问我哪里操作有误?这种方式是否可行?
解决方案
这种方式完全可行,你的问题出在以下几个常见疏漏:
1. 未等待预取操作完成
prefetch是异步函数,你没有添加await就直接调用dehydrate(),导致服务端还没完成数据预取就生成了空的脱水状态。修改getServerSideProps:
export const getServerSideProps = async (ctx: GetServerSidePropsContext<{ id: string }>) => { const helpers = generateSSGHelper() const id = ctx.params?.id if (typeof id !== 'string') throw new Error('no id') // 必须await预取完成 await helpers.partner.getById.prefetch({ id }) return { props: { trpcState: helpers.dehydrate(), id, } } }
2. 组件未注入脱水状态
你的组件没有接收trpcState props,也没有通过TRPC的Hydrate组件把脱水状态注入客户端查询缓存。修改组件:
import { Hydrate } from '@trpc/next'; // 补充trpcState的props类型 const SinglePartnerPage: NextPage<{ id: string; trpcState: any }> = ({ id, trpcState }) => { const partner = api.partner.getById.useQuery({ id }); if (partner.status !== 'success') { console.log('Loading!!') return <>Loading...</> } return ( <Hydrate state={trpcState}> {/* 你的页面内容 */} </Hydrate> ) }
3. 上下文一致性检查
即使你没在generateSSGHelper中使用req & res,也要确保服务端生成的TRPC上下文和客户端使用的上下文完全匹配(比如用户认证状态、地域信息等)。如果上下文不匹配,TRPC会认为这是一个新的查询,重新发起请求而非使用预取的数据。
内容的提问来源于stack exchange,提问作者Raul Calvo
相关产品推荐
相关产品推荐

