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

ReactJS/LaravelAPI:如何将嵌套数组值传递至另一个组件

解决方案

先修正现有代码的一个问题

你的FarmDetails组件中,farm的初始状态是空字符串'',当尝试访问farm.fruits时会抛出类型错误(字符串没有fruits属性)。请将初始状态改为空对象:

const [farm, setFarm] = useState({});

方案一:通过条件渲染展示水果列表(无需额外路由)

适合在同一页面内切换显示/隐藏水果列表。

1. 创建FruitList组件

function FruitList({ fruits }) {
  // 处理无数据情况
  if (!fruits || fruits.length === 0) {
    return <p>该农场暂无水果数据</p>;
  }

  return (
    <div className="fruit-list-container">
      <h3>农场水果清单</h3>
      <ul>
        {fruits.map((fruit, index) => (
          <li key={index} className="fruit-item">
            {/* 根据API返回的fruit字段调整渲染内容 */}
            <p>名称:{fruit.name}</p>
            <p>数量:{fruit.quantity}</p>
            <p>成熟度:{fruit.ripeness}</p>
          </li>
        ))}
      </ul>
    </div>
  );
}

2. 修改FarmDetails组件

添加控制显示状态的变量、切换按钮,并渲染FruitList:

function FarmDetails() {
  let navigate = useNavigate();
  // 修正初始状态
  const [farm, setFarm] = useState({});
  const { username, farmId } = useParams(); // 合并解构写法更简洁
  const [isLoading, setIsLoading] = useState(true);
  const user = React.useContext(UserContext);
  // 添加状态控制水果列表显示
  const [showFruits, setShowFruits] = useState(false);

  useEffect(() => {
    let isMounted = true;

    axios.get(`/api/farm/${username}/${farmId}`).then(res => {
      if (isMounted) {
        if (res.data.status === 200) {
          setFarm(res.data.farm);
          setIsLoading(false);
        }
        else if (res.data.status === 404) {
          navigate('/');
          toast.error(res.data.message, "error");
        }
      }
    }).catch(err => {
      // 添加错误捕获
      if (isMounted) {
        toast.error("请求失败,请稍后重试", "error");
        setIsLoading(false);
      }
    });

    return () => {
      isMounted = false;
    };
  }, [username, farmId, navigate]); // 添加依赖项,避免lint警告

  if (isLoading) {
    return <div>加载中...</div>;
  }

  return (
    <div className="farm-details-container">
      <h2>{farm.name} 详情</h2>
      <p>农场主:{username}</p>
      <p>地址:{farm.address}</p>
      {/* 切换按钮 */}
      <button 
        onClick={() => setShowFruits(!showFruits)}
        className="toggle-fruits-btn"
      >
        {showFruits ? '隐藏水果列表' : '查看水果列表'}
      </button>
      {/* 条件渲染水果列表 */}
      {showFruits && <FruitList fruits={farm.fruits} />}
    </div>
  );
}

方案二:通过嵌套路由展示水果列表(符合路由规范)

适合将水果列表作为独立路由页面,支持浏览器前进后退。

1. 修改路由配置

添加嵌套路由,让FarmDetails作为父路由,水果列表作为子路由:

import { Routes, Route } from 'react-router-dom';
import FarmDetails from './FarmDetails';
import FruitList from './FruitList';

// 路由配置
<Routes>
  {/* 其他路由 */}
  <Route path="farm-details/:username/:farmId" element={<FarmDetails />}>
    {/* 嵌套路由:农场下的水果列表 */}
    <Route path="fruits" element={<FruitList />} />
  </Route>
</Routes>

2. 改造FarmDetails组件

导入Outlet用于渲染子路由,添加跳转按钮:

import { useNavigate, useParams, Outlet } from 'react-router-dom';

function FarmDetails() {
  let navigate = useNavigate();
  const [farm, setFarm] = useState({});
  const { username, farmId } = useParams();
  const [isLoading, setIsLoading] = useState(true);
  const user = React.useContext(UserContext);

  useEffect(() => {
    // 原请求逻辑不变,修正依赖项
    let isMounted = true;
    axios.get(`/api/farm/${username}/${farmId}`).then(res => {
      if (isMounted) {
        if (res.data.status === 200) {
          setFarm(res.data.farm);
          setIsLoading(false);
        } else if (res.data.status === 404) {
          navigate('/');
          toast.error(res.data.message, "error");
        }
      }
    }).catch(err => {
      if (isMounted) {
        toast.error("请求失败", "error");
        setIsLoading(false);
      }
    });
    return () => isMounted = false;
  }, [username, farmId, navigate]);

  if (isLoading) {
    return <div>加载中...</div>;
  }

  return (
    <div className="farm-details-container">
      <h2>{farm.name} 详情</h2>
      <p>农场主:{username}</p>
      <p>地址:{farm.address}</p>
      {/* 跳转到嵌套路由 */}
      <button onClick={() => navigate('fruits')}>查看水果列表</button>
      {/* 渲染子路由(水果列表会在这里显示) */}
      <Outlet context={{ farm }} />
    </div>
  );
}

3. 创建FruitList组件

通过useOutletContext获取父路由传递的farm数据:

import { useOutletContext, useNavigate } from 'react-router-dom';

function FruitList() {
  const navigate = useNavigate();
  const { farm } = useOutletContext();

  if (!farm?.fruits || farm.fruits.length === 0) {
    return (
      <div className="no-fruits">
        <p>该农场暂无水果数据</p>
        <button onClick={() => navigate('..')}>返回农场详情</button>
      </div>
    );
  }

  return (
    <div className="fruit-list-container">
      <h3>{farm.name} 的水果清单</h3>
      <button onClick={() => navigate('..')}>返回农场详情</button>
      <ul>
        {farm.fruits.map((fruit, id) => (
          <li key={id} className="fruit-item">
            <p>名称:{fruit.name}</p>
            <p>数量:{fruit.quantity}</p>
            <p>成熟度:{fruit.ripeness}</p>
          </li>
        ))}
      </ul>
    </div>
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 14:40:15