使用fetch和map获取复杂JSON中指定字段值的问题
无法访问复杂JSON嵌套字段的解决方案
问题重现
尝试从嵌套JSON中读取字段(如match.teams.home)时,出现Cannot read properties of undefined (reading 'home')错误,相关JSON结构和代码如下:
目标JSON结构
{"get": "fixtures", "parameters": { "date": "2024-01-17" }, "errors": [], "results": 218, "paging": { "current": 1, "total": 1 }, "response": [ { "fixture": { "id": 1156472, "referee": null, "timezone": "UTC", "date": "2024-01-17T00:00:00+00:00", "timestamp": 1705449600, "periods": { "first": null, "second": null }, "venue": { "id": null, "name": "TBC", "city": "TBC" }, "status": { "long": "Time to be defined", "short": "TBD", "elapsed": null } }, "league": { "id": 667, "name": "Friendlies Clubs", "country": "World", "logo": "https://media.api-sports.io/football/leagues/667.png", "flag": null, "season": 2024, "round": "Club Friendlies 3" }, "teams": { "home": { "id": 675, "name": "Vasas", "logo": "https://media.api-sports.io/football/teams/675.png", "winner": null }, "away": { "id": 646, "name": "Levski Sofia", "logo": "https://media.api-sports.io/football/teams/646.png", "winner": null } }, "goals": { "home": null, "away": null }, "score": { "halftime": { "home": null, "away": null }, "fulltime": { "home": null, "away": null }, "extratime": { "home": null, "away": null }, "penalty": { "home": null, "away": null } } } ]}
你的代码
let url = "http://localhost:8000/home/"; const [matches, setMatches] = useState([{}]); const matchData = async () => { const res = await fetch(url); const d = await res.json(); return setMatches(d.response); } useEffect(() => { matchData(); }, [{}]);
解决步骤
1. 修正初始状态
初始状态设为[{}]会导致组件首次渲染时,map遍历到空对象,访问teams时直接返回undefined,进而引发读取home的错误。将初始状态改为空数组:
const [matches, setMatches] = useState([]);
2. 修复useEffect依赖
[{}]作为依赖时,每次渲染都会生成新的空对象,导致useEffect无限触发请求。改为空数组,确保仅在组件挂载时执行一次:
useEffect(() => { matchData(); }, []);
3. 处理异步加载的空值情况
数据加载完成前,matches是空数组,需通过条件渲染或可选链操作符避免访问未定义属性:
方式一:条件渲染
{matches.length > 0 ? ( matches.map(match => ( <div key={match.fixture.id}> {match.teams.home.name} vs {match.teams.away.name} <p>比赛时间:{match.fixture.date}</p> </div> )) ) : ( <div>加载中...</div> )}
方式二:可选链操作符(推荐)
通过?.自动处理未定义的中间属性,避免报错:
matches.map(match => ( <div key={match.fixture?.id}> {match.teams?.home?.name} vs {match.teams?.away?.name} <p>比赛时间:{match.fixture?.date}</p> </div> ))
4. 增加请求错误处理
防止请求失败或返回数据结构异常导致的报错,在异步函数中添加try/catch:
const matchData = async () => { try { const res = await fetch(url); if (!res.ok) throw new Error(`请求失败:${res.status}`); const d = await res.json(); // 确保即使response不存在,也设置为空数组 setMatches(d.response || []); } catch (err) { console.error('数据获取失败:', err); setMatches([]); } }
内容的提问来源于stack exchange,提问作者Technic IT
相关产品推荐
相关产品推荐

