React渲染fetch对象数组及多组数据存state实现方法
问题根因
所有渲染异常都来自对接口返回的数据结构判断错误:
- 接口返回的
response是餐厅对象构成的数组,不是单个对象,因此直接读取response.meniu会得到undefined——数组类型本身不存在meniu属性 - 每个餐厅对象下的
meniu字段同样是菜品对象构成的数组,不是单个菜品对象,因此直接写user.meniu.pret无法读取到值:数组不存在pret属性。user.meniu[0].pret能正常显示值,刚好印证了meniu是数组类型,[0]是读取数组中第一个菜品的价格。 - 代码中连续两次调用
setMeniu,后一次的赋值会覆盖前一次的结果,最终meniu状态存储的永远是undefined。 useState未设置对应类型的初始值,首次渲染时users为undefined,虽然后续加了users &&的判断做拦截,但写法冗余。
正确实现代码
import { useState, useEffect } from 'react'; function App() { // 初始值设为空数组,和接口返回类型对齐 const [users, setUsers] = useState([]); const getApiData = async () => { const res = await fetch("https://vercelfastfoodapi.vercel.app/fastfood/"); const data = await res.json(); // 接口直接返回餐厅数组,直接存入状态即可 setUsers(data); }; useEffect(() => { getApiData(); }, []); return ( <div className="App"> {users.map((user) => ( <div className="item-container" key={user._id}> <p>餐厅名称:<b>{user.restaurant}</b></p> <p>菜品列表:</p> <ul> {/* meniu是数组,需要二次遍历才能渲染所有菜品,不能直接取.pret */} {user.meniu?.map((dish, idx) => ( <li key={idx}> 菜品名:{dish.nume} —— 价格:{dish.pret} </li> ))} </ul> </div> ))} </div> ); } export default App;
修正点说明
- 移除了冗余的
meniu全局状态:渲染全量餐厅的所有菜品时,不需要单独提取某一个餐厅的菜品数组存为全局状态,遍历users数组时嵌套遍历每个餐厅对应的meniu数组即可 - 给
useState设置初始值为空数组[],和接口返回的数组类型对齐,不需要额外写users &&的非空判断,减少边界判断代码 - 访问
user.meniu时增加可选链操作符?.,兼容接口返回异常、个别餐厅无菜品数据的边界场景,避免页面白屏报错 - 对每个餐厅下的
meniu数组做二次遍历,即可渲染出该餐厅所有菜品的价格、名称等信息,解决只能显示第一个菜品价格的问题 - 删除了重复的
setMeniu调用,避免后一次赋值覆盖前一次有效值的问题。
如果业务需求确实需要单独存储某一家餐厅的菜品列表(比如索引为1的餐厅),只保留对应赋值语句即可,不要连续两次调用
setMeniu造成值覆盖。
内容的提问来源于stack exchange,提问作者JohnnyTheHobo
相关产品推荐
相关产品推荐

