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

直接访问动态路由时React useEffect钩子无法获取数据问题

问题分析

你的问题根源在于两处关键逻辑错误:

  1. Context组件的useEffect中,在异步请求未完成时就调用了setIsLoading(false),导致加载状态提前结束,同时初始渲染时products始终是空数组。
  2. 直接访问动态路由时,ProductDetails组件会在数据加载完成前尝试从空数组中查找产品,引发product为undefined的报错。

解决方案

1. 修复Context组件的异步请求逻辑

调整useEffect中的代码,确保只有请求完成(成功或失败)时才更新加载状态,同时新增错误状态用于异常处理:

import { useState, useEffect } from "react";
import ProductContext from "./product-context";

const ProductContextProvider = (props) => {
  const [Products, setProducts] = useState([]);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchedData = async () => {
      setIsLoading(true);
      setError(null);
      try {
        const response = await fetch("https://fakestoreapi.com/products/");
        if (!response.ok) {
          throw new Error("Something Went Wrong");
        }
        const data = await response.json();
        setProducts(data);
      } catch (error) {
        setError(error.message);
      } finally {
        // 请求完成(成功/失败)后统一关闭加载状态
        setIsLoading(false);
      }
    };

    fetchedData();
  }, []);

  return (
    <ProductContext.Provider
      value={{ isLoading, products: Products, error }}
    >
      {props.children}
    </ProductContext.Provider>
  );
};

export default ProductContextProvider;

2. 优化ProductDetails组件的边界情况处理

直接在组件中使用Context,无需通过路由传递props,并处理加载中、错误、产品不存在的场景:

import React, { useContext } from "react";
import { useParams, Navigate } from "react-router-dom";
import NavBar from "../Components/Navigaiton-Bar/NavBar";
import Card from "../UI/Card";
import ProductContext from "../Store/product-context";

const ProductDetails = () => {
  const params = useParams();
  const { isLoading, products, error } = useContext(ProductContext);
  const productId = +params.productId;
  const product = products.find(pro => pro.id === productId);

  // 加载中状态
  if (isLoading) {
    return (
      <>
        <NavBar />
        <div className="flex items-center justify-center h-screen">
          <p>加载产品详情中...</p>
        </div>
      </>
    );
  }

  // 错误状态
  if (error) {
    return (
      <>
        <NavBar />
        <Card>
          <div className="text-center p-8">
            <p>错误:{error}</p>
          </div>
        </Card>
      </>
    );
  }

  // 产品不存在时跳转到首页
  if (!product) {
    return <Navigate to="/" />;
  }

  return (
    <>
      <NavBar />
      <Card>
        <div className="flex items-center justify-center flex-wrap">
          <div className="flex items-center w-full h-[100vh] ">
            <div className="m-10">
              <img
                className="w-[800px] h-[300px]"
                alt="产品图"
                src={product.image}
              ></img>
            </div>
            <div>
              <p>{product.title}</p>
              <p>${product.price}</p>
              <p>{product.description}</p>
              <button>Add To Cart</button>
            </div>
          </div>
        </div>
      </Card>
    </>
  );
};

export default ProductDetails;

3. 简化路由组件

由于ProductDetails直接使用Context,路由组件无需再传递products props:

import { Route, Routes, useLocation } from "react-router-dom";
import { AnimatePresence } from "framer-motion";
import ProductDetails from "../Pages/ProductDetails";
import Home from "../Pages/Home";

const AnimatedRoutes = () => {
  const location = useLocation();

  return (
    <AnimatePresence>
      <Routes location={location} key={location.pathname}>
        <Route path="/" element={<Home />} />
        <Route path="/products/:productId" element={<ProductDetails />} />
      </Routes>
    </AnimatePresence>
  );
};

export default AnimatedRoutes;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 01:32:18