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

NextJS 13页面预渲染报错:Relay查询缺productId参数如何解决

Next.js 构建时Relay查询因缺少参数失败的解决方案

问题背景

在构建pages/productDetail.tsx组件时触发预渲染错误,报错信息如下:

Error occurred prerendering page "/productDetail".
RelayNetwork: No data returned for operation productStateByKeyQuery, got error(s):
Variable id is required.

开发环境(npm run dev)下,带productId参数的URL能正常加载数据,但构建阶段预渲染时无法获取URL参数,导致Relay查询因缺少必填的id变量失败。

解决方案

方案1:禁用页面预渲染(客户端动态渲染)

通过next/dynamic导入组件并关闭服务端渲染,让页面仅在客户端加载后再执行查询:

// pages/productDetail.tsx
import dynamic from 'next/dynamic';

// 动态导入组件,禁用服务端渲染
const ProductDetail = dynamic(() => import('./components/ProductDetail'), {
  ssr: false,
  loading: () => <div>Loading...</div>
});

export default ProductDetail;

将原组件代码拆分到components/ProductDetail.tsx中(保持原逻辑不变),这样预渲染阶段不会执行Relay查询,客户端加载完成后会获取URL中的productId并执行查询。

方案2:使用getServerSideProps实现服务端渲染

getServerSideProps会在每次请求时运行,可直接获取URL参数,适合需要SEO优化的场景。修改后的组件代码如下:

// pages/productDetail.tsx
import React from 'react';
import { usePreloadedQuery, preloadQuery } from 'react-relay';
import { RelayEnvironmentProvider } from 'react-relay';
import environment from '@/relay/environment'; // 你的Relay环境配置

import { productStateByKeyQuery } from '@/queries/productStateByKey';
import type { productStateByKeyQuery as qt } from '@/queries/__generated__/productStateByKeyQuery.graphql';

// 服务端获取参数并预加载查询
export async function getServerSideProps(context) {
  const productId = context.query.productId;

  // 无参数时重定向到首页或返回404
  if (!productId) {
    return {
      redirect: {
        destination: '/',
        permanent: false,
      },
    };
  }

  const queryRef = preloadQuery(
    environment,
    productStateByKeyQuery,
    { id: productId }
  );

  return { props: { queryRef } };
}

export default function ProductDetail({ queryRef }) {
  const data = usePreloadedQuery<qt>(productStateByKeyQuery, queryRef);

  return (
    <RelayEnvironmentProvider environment={environment}>
      <div>ProductDetail {data.productStateByKey?.id}</div>
      <div>ID: {data.productStateByKey?.id}</div>
      <div>Version: {data.productStateByKey?.version}</div>
      <div>Product code: {data.productStateByKey?.product?.code}</div>
    </RelayEnvironmentProvider>
  );
}

注意:需确保Relay环境在服务端能正常初始化,避免因环境配置差异导致服务端渲染失败。

方案3:组件内参数判断(有限场景适用)

在组件内判断productId是否存在,仅当参数有效时执行查询:

// pages/productDetail.tsx
import { useRouter } from 'next/router';
import React from 'react';
import { useLazyLoadQuery } from 'react-relay';

import { productStateByKeyQuery } from '@/queries/productStateByKey';
import type { productStateByKeyQuery as qt } from '@/queries/__generated__/productStateByKeyQuery.graphql';

export default function ProductDetail() {
  const router = useRouter();
  const productId = router.query.productId;

  // 仅当productId存在时执行查询
  const data = productId ? useLazyLoadQuery<qt>(
    productStateByKeyQuery,
    { id: productId },
    { fetchPolicy: 'store-or-network' }
  ) : null;

  // 未获取到参数时显示加载状态
  if (!productId) {
    return <div>Loading...</div>;
  }

  return (
    <>
      <div>ProductDetail {productId}</div>
      <div>ID: {data?.productStateByKey?.id}</div>
      <div>Version: {data?.productStateByKey?.version}</div>
      <div>Product code: {data?.productStateByKey?.product?.code}</div>
    </>
  );
}

注意:此方案可能仍会触发预渲染错误,因为Next.js预渲染时router.query为空,useLazyLoadQuery的条件判断可能无法阻止查询执行,仅作为补充方案。

方案选择建议

  • 无需SEO优化:优先选方案1,实现简单,避免预渲染问题。
  • 需要SEO优化:优先选方案2,通过服务端渲染获取数据并生成可被搜索引擎抓取的页面。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 20:13:17