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
相关产品推荐
相关产品推荐

