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

使用React Router时useEffect未正常执行问题求解

问题根因

你观察到useEffect完全不执行、item状态从未赋值,核心原因是组件首次渲染就抛出运行时错误,导致挂载流程中断,useEffect根本没有执行机会,具体触发逻辑:

  • 你给item设置的初始值是空对象{}
  • React组件的首次渲染发生在useEffect执行之前,此时渲染代码里会执行item.price.toFixed(2),但空对象下price属性值为undefined,直接调用toFixed方法会抛出TypeError: Cannot read properties of undefined (reading 'toFixed')
  • 渲染阶段报错后React会直接中断当前组件的挂载流程,而useEffect属于组件挂载完成后才会触发的钩子,组件没挂载成功自然永远不会执行,你写在effect里的console.log("Fetching")日志也不会打印。打开浏览器开发者工具的Console面板,就能看到对应的红色报错信息。

除此之外你的代码还有几个潜在问题,就算修复了渲染报错也可能导致功能异常:

  • 路由钩子useParams()拿到的id是字符串类型,如果后端接口期望接收数字类型ID,直接传字符串可能导致接口匹配不到对应资源,返回404或错误数据
  • 单条商品查询接口的返回值通常不会把单条数据放在Items字段下,你写的setItem(data["Items"])大概率取错了返回字段,就算接口请求成功也可能给item赋成undefined或者数组,导致后续渲染异常
  • 你写在fetch调用后的console.log("Fetched")是同步代码,会在fetch请求刚发出、还没拿到响应的时候就执行,根本不会等请求返回,不能用来判断接口是否请求完成。
修复方案
  • 给item设置和渲染逻辑匹配的初始值,或者用可选链、加载状态兜底,避免初始渲染阶段访问不存在的属性报错
  • 按需转换路由参数的类型,匹配后端接口的参数要求
  • 接口请求成功后先打印返回值,确认实际数据结构,再写对应的取值逻辑,不要臆测字段名
  • 接口请求相关的日志、后续逻辑要写到.then/.catch/.finally的异步回调里,不要写在fetch调用的同步代码段中

修正后的Item.jsx代码参考:

import React, { useState, useEffect } from "react";
import { useParams } from "react-router-dom";
 
function Item() {
  // 补全初始值的字段结构,从根源避免首次渲染访问属性报错
  const [item, setItem] = useState({
    name: "加载中",
    quantity: 0,
    price: 0,
    description: ""
  });
  const [loading, setLoading] = useState(true);
  // 将路由拿到的字符串ID转为数字,匹配后端参数要求
  const id = Number(useParams().id || 0);

  useEffect(() => {
    console.log("开始请求商品数据");
    setLoading(true);
    fetch(`http://localhost:8080/item/${id}`)
      .then((res) => {
        if (!res.ok) throw new Error("接口请求失败");
        return res.json();
      })
      .then((data) => {
        console.log("接口返回数据:", data);
        // 请根据控制台打印的实际返回结构调整取值,单条查询通常直接返回商品对象,不需要取Items字段
        setItem(data);
      })
      .catch(err => console.error("获取商品数据失败:", err))
      .finally(() => {
        setLoading(false);
        console.log("请求流程结束");
      });
  }, [id]);

  if (loading) return <div className="p-3">商品信息加载中...</div>
 
  return (
    <div key={id}>
      <h1>{item.name}</h1>
      <h2 className="px-3">Quantity: {item.quantity}</h2>
      <h2 className="px-3">Price: ${item.price.toFixed(2)}</h2>
      <h2 className="px-3">Description: {item.description}</h2>
    </div>
  );
}
export default Item;

补充说明:你贴的路由配置文件Index.js没有逻辑问题,/item/:id的路由和Item组件的绑定是正确的,不需要修改。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 10:18:30