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

React-Router-DOM v6动态路由问题:useParams获取id为undefined

问题解决:React-Router-DOM v6 动态路由id获取undefined

问题现象

使用React和React-Router-DOM v6搭建电商商品详情页时,从商品列表页点击卡片跳转后,详情页通过useParams()获取的id为undefined;但手动在浏览器URL中输入/products/17这类带id的地址时,控制台能正常获取id并请求到数据。

错误原因分析

  1. Products组件的Link配置错误:你将整个商品列表包裹在单个<Link>标签中,且链接地址使用products.id——但products是数组,不存在id属性,导致生成的链接为/products/undefined,跳转后详情页无法获取有效id。
  2. 路由顺序问题:App.js中path="/*"的404路由放在了动态路由/products/:id前面,React-Router会优先匹配第一个符合规则的路由,导致动态路由被404路由拦截(手动输入URL暂时生效属于偶然情况)。

修复方案

1. 修正Products组件的Link位置与参数

将<Link>标签移至每个商品卡片内部,使用当前遍历项的item.id作为动态参数:

修改后的Products组件核心代码:

// 移除外层包裹整个列表的Link
<div className="p3-5 prods">
  {products.map((item, index) => {
    const { brand, image_url, price, rating, title, id } = item; // 解构出当前商品的id

    return (
      <Link key={index} to={`/products/${id}`}> {/* 每个卡片对应独立的跳转链接 */}
        <div className="product-container">
          <img src={image_url} alt={title} className="map-image" /> {/* 补充图片alt文本 */}
          <div className="card-body">
            <h5 className="card-title text-center pt-2">
              {title.substr(0, 30)}
            </h5>
            <p className="card-text text-center">{`by ${brand}`}</p>
            <p className="text-center price">{`₹ ${price}`}</p>
            <p className="ratings text-center">{`⭐  ${rating}`}</p>
            <div className="btns text-center">
              <button className="btns">
                Add to Cart{<ShoppingCart />}{" "}
              </button>
            </div>
          </div>
        </div>
      </Link>
    );
  })}
</div>

2. 调整App.js的路由顺序

将404路由移至所有路由的最后,确保动态路由能被正确匹配:

修改后的App.js路由部分:

<Routes>
  <Route path="/" element={<Protected Comp={Home} />} />
  <Route path="/login" element={<Login />} />
  <Route path="/carts" element={<Protected Comp={Carts} />} />
  <Route path="/products" element={<Protected Comp={Products} />} />
  <Route path="/products/:id" element={<ProductsDetailPage />} /> {/* 动态路由放在404路由之前 */}
  <Route path="/*" element={<Page404 />} /> {/* 404路由作为兜底,放在最后 */}
</Routes>

3. 可选优化:ProductsDetailPage组件

添加加载状态与空值判断,避免无效请求:

function ProductsDetailPage() {
  const [product, setProduct] = useState(null); // 单个商品数据,变量名改为product更准确
  const [loading, setLoading] = useState(true);
  const { id } = useParams();

  const getProductDetails = async () => {
    if (!id) return; // 无有效id时不发起请求
    setLoading(true);
    try {
      const jwtToken = Cookies.get("jwt_token");
      const apiUrl = `https://apis.ccbp.in/products/${id}`;
      const options = {
        headers: { Authorization: `Bearer ${jwtToken}` },
        method: "GET",
      };
      const response = await fetch(apiUrl, options);
      const data = await response.json();
      setProduct(data.product); // API返回的是单个商品对象,而非数组
    } catch (error) {
      console.error("Error fetching data:", error);
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => {
    getProductDetails();
  }, [id]);

  if (loading) return <div>Loading...</div>;
  if (!product) return <div>Product not found</div>;

  return (
    <>
      <h1>{product.title}</h1>
      <img src={product.image_url} alt={product.title} />
      <p>Brand: {product.brand}</p>
      <p>Price: ₹{product.price}</p>
      <p>Rating: ⭐ {product.rating}</p>
      {/* 其他商品详情字段 */}
    </>
  );
}

验证效果

修改完成后,点击商品卡片会生成/products/[id]格式的正确链接,跳转至详情页后,useParams()能正常获取id并请求到对应商品数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 09:45:05