You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Query SSR模式prefetchQuery未触发请求问题排查

问题根因

SSR预取失效、返回的dehydratedState无法被客户端命中,核心由两个问题导致:

  1. codegen.yml 配置语法错误,fetcher相关配置未正确嵌套,导致生成的queryKey、fetcher方法逻辑异常
  2. 服务端预取和客户端调用时生成的queryKey不匹配,hydration阶段无法命中服务端预取的缓存

修复步骤

1. 修正codegen.yml配置

原配置中fetcher字段的嵌套结构错误,graphql-request的端点配置没有正确归属到fetcher配置下,修正后配置如下:

overwrite: true
schema: "https://api.spacex.land/graphql/"
documents: "./src/graphql/**/*.gql"
generates:
  src/generated.ts:
    plugins:
      - typescript
      - typescript-operations
      - typescript-react-query
    config:
      pureMagicComment: true
      exposeQueryKeys: true
      exposeFetcher: true
      fetcher:
        func: graphql-request
        endpoint: "https://api.spacex.land/graphql/"
        fetchParams:
          headers:
            Content-Type: "application/json"

配置修改后重新执行代码生成命令,输出最新的generated.ts文件。

2. 对齐服务端与客户端的queryKey

typescript-react-query生成的getKey()方法会将查询变量作为queryKey的一部分,格式为[查询名称, 变量对象]。原代码中服务端调用getKey()时未传入变量,和客户端传入{limit:5}生成的queryKey完全不一致,无法命中缓存。
同时原代码中存在两个冗余/错误写法:

  • 手动给生成的hook传入TS泛型,生成的hook已经内置完整类型,额外传泛型可能导致类型推断异常
  • 对dehydrate结果做JSON.parse(JSON.stringify())序列化,Next.js会自动处理props的序列化,该操作无意义
    修正后的页面代码如下:
// index.tsx
import type { NextPage } from 'next'
import Head from 'next/head'
import { QueryClient, dehydrate} from "react-query"
import { useGetLaunchesPastQuery } from '../generated';

const Home: NextPage = () => {
  // 移除多余泛型,传入和服务端预取完全一致的变量
  const { data, isFetching } = useGetLaunchesPastQuery({ limit: 5 });

  return (
    <div className={styles.container}>
      <Head>
        <title>Create Next App</title>
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <main className={styles.main}>
        {data?.launchesPast && (
          <ul>
            {data.launchesPast.map((launch) => (
              <li key={launch?.mission_name}>{launch?.mission_name} ({launch?.launch_date_local})</li>
            ))}
          </ul>
        )}
      </main>
    </div>
  );
}

export const getServerSideProps = async () => {
  const queryClient = new QueryClient();
  // 定义和客户端完全一致的查询变量,保证queryKey对齐
  const queryVariables = { limit: 5 };

  await queryClient.prefetchQuery(
    useGetLaunchesPastQuery.getKey(queryVariables),
    useGetLaunchesPastQuery.fetcher(queryVariables)
  );

  return {
    props: {
      dehydratedState: dehydrate(queryClient),
    },
  };
};

export default Home

注意事项

如果服务端预取和客户端使用的查询变量不一致(比如服务端预取limit=10,客户端传limit=5),属于queryKey不匹配的场景,客户端会自动发起新请求,是React Query的预期行为,要实现SSR首屏带数据,必须保证两边查询名称、查询变量完全一致。

内容的提问来源于stack exchange,提问作者wsfuller

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 16:51:42