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

Next.js 13动态路由无法获取id及数据问题排查求助

问题分析:路由参数获取失败,无法匹配产品数据

核心故障原因

  1. 参数获取方式完全错误:你的路由是/Product/Category/id这种动态路径参数,但你用了useSearchParams()——这个API专门用来获取URL中?id=xxx格式的查询参数,和你的路由结构不匹配,所以拿到的id必然是null。
  2. Pages Router API误用:你之前尝试的getStaticProps/getStaticPaths是Next.js Pages Router的专属API,而你的代码标注了"use client",属于App Router环境,这两个方法在App Router里完全无效。
  3. 次要风险:字符串转数字的边界情况:即使后续拿到id,如果id是undefined,Number(id)会得到NaN,导致find匹配失败,但这不是当前id为null的核心原因。

修复方案

1. 正确获取动态路由参数

替换useSearchParams()为App Router的useParams()API,这是获取路径动态参数的正确方式:

"use client";
import SinglePSlider from "../../../Component/SinglePSlider";
import Navbar from "../../../Navbar/page";
import "../../../globals.css";
import { useEffect, useState } from "react";
// 替换useSearchParams为useParams
import { useParams } from "next/navigation";

interface productItem {
  id?: number;
  name: string;
  image1: string;
  image2: string;
  image3: string;
  image4: string;
  description: string;
  price?: string;
  prices: {
    half: string;
    full: string;
  };
  categories: string;
}

const Item = () => {
  // 获取动态路由中的id参数
  const params = useParams();
  const id = params.id as string | undefined;

  const [product, setProduct] = useState<productItem | null>(null);

  useEffect(() => {
    const fetchData = async () => {
      const res = await fetch(`/items.json`);
      const data = await res.json();
      // 处理id为undefined的情况,避免Number(undefined)得到NaN
      const targetId = id ? Number(id) : -1;
      const productItem = data.Cakes.find(
        (item: productItem) => item.id === targetId
      );
      setProduct(productItem);
    };

    if (id) {
      fetchData();
    }
  }, [id]);

  // 其余代码保持不变
  return (
    <>
      <Navbar />
      <div className="singleproduct-main">
        <div className="singleproduct-parallex">
          <SinglePSlider
            img1={product?.image1 || ""}
            img2={product?.image2 || ""}
            img3={product?.image3 || ""}
            img4={product?.image4 || ""}
          />
        </div>
        <div className="singleproduct">
          <h4 className="singleproduct-title">{product?.name}</h4>
          <div className="singleproduct-franchise">
            <select>
              <option disabled selected value="">
                Select Franchise
              </option>
              <option value=""></option>
            </select>
          </div>
          <p className="singleproduct-para">{product?.description}</p>
        </div>
      </div>
    </>
  );
};

export default Item;

2. 静态生成页面的正确姿势(App Router)

如果需要静态生成该页面,用App Router的generateStaticParams()替代getStaticPaths,并可改为服务器组件(无需客户端交互时移除"use client"):

// 移除"use client",改为服务器组件
import SinglePSlider from "../../../Component/SinglePSlider";
import Navbar from "../../../Navbar/page";
import "../../../globals.css";

interface productItem {
  id?: number;
  name: string;
  image1: string;
  image2: string;
  image3: string;
  image4: string;
  description: string;
  price?: string;
  prices: {
    half: string;
    full: string;
  };
  categories: string;
}

// 静态生成所有可能的路由参数
export async function generateStaticParams() {
  // 开发环境需使用完整URL,生产环境可使用相对路径
  const res = await fetch("http://localhost:3000/items.json");
  const data = await res.json();
  return data.Cakes.map((cake: productItem) => ({
    id: cake.id?.toString(),
  }));
}

// 直接在组件中获取路由参数并fetch数据
async function Item({ params }: { params: { id: string } }) {
  const res = await fetch(`/items.json`);
  const data = await res.json();
  const targetId = Number(params.id);
  const product = data.Cakes.find(
    (item: productItem) => item.id === targetId
  );

  if (!product) {
    return <div>Product not found</div>;
  }

  return (
    <>
      <Navbar />
      <div className="singleproduct-main">
        <div className="singleproduct-parallex">
          <SinglePSlider
            img1={product.image1}
            img2={product.image2}
            img3={product.image3}
            img4={product.image4}
          />
        </div>
        <div className="singleproduct">
          <h4 className="singleproduct-title">{product.name}</h4>
          <div className="singleproduct-franchise">
            <select>
              <option disabled selected value="">
                Select Franchise
              </option>
              <option value=""></option>
            </select>
          </div>
          <p className="singleproduct-para">{product.description}</p>
        </div>
      </div>
    </>
  );
}

export default Item;

3. 验证路由结构

确保你的文件夹结构符合App Router要求:

app/
└── Product/
    └── Category/
        └── [id]/
            └── page.tsx

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 22:47:51