React中useEffect首次渲染后报错?REST Countries API调用问题
React调用REST Countries API时"无法读取undefined"问题解决
问题场景
开发React应用调用REST Countries API,希望组件首次渲染时发起请求,使用了空依赖的useEffect,但运行时出现"无法读取undefined"的错误,代码如下:
const LightMode = () => { const data = useRef([]) useEffect(() =>{ axios.get('https://restcountries.com/v3.1/all').then(res=>{ res.data.forEach(country =>{ data.current.push({ name: country.name.common, population: country.population, region: country.region, capital: country.capital, image: country.coatOfArms.png }) }) }) }, []) console.log(data) return( <div> <NavigationBar /> <div className='temp'> <Card className='country-cards'> <Card.Img variant='top' src={data[0].image}/> <Card.Body> <Card.Title></Card.Title> </Card.Body> </Card> </div> </div> ) }
错误原因
- 异步请求时序问题:
useEffect确实会在组件首次渲染后执行,但API请求是异步操作——组件首次渲染时,请求还未返回结果,此时data.current是空数组,data.current[0]为undefined,访问.image就会抛出"无法读取undefined的image属性"的错误。 - 状态存储工具误用:
useRef的更新不会触发组件重新渲染,就算API请求完成后data.current有了数据,组件也不会重新渲染展示新内容,这类需要驱动视图更新的数据应该用useState管理。 - useRef访问方式错误:
useRef的实际值存在.current属性中,你代码里写的data[0].image是错误写法,正确应为data.current[0]?.image,但这只能临时规避报错,解决不了根本问题。
修正方案
把useRef换成useState管理数据,同时在渲染时做条件判断,确保有数据后再渲染对应内容:
import { useState, useEffect } from 'react'; import axios from 'axios'; const LightMode = () => { // 用useState管理需渲染的数据,初始化为空数组 const [countries, setCountries] = useState([]); useEffect(() => { axios.get('https://restcountries.com/v3.1/all') .then(res => { // 转换数据格式后直接设置状态,触发组件重新渲染 const formattedCountries = res.data.map(country => ({ name: country.name.common, population: country.population, region: country.region, capital: country.capital, image: country.coatOfArms.png })); setCountries(formattedCountries); }) .catch(err => { // 增加错误处理,避免请求失败无提示 console.error('请求国家数据失败:', err); }); }, []); return ( <div> <NavigationBar /> <div className='temp'> {/* 先判断是否有数据,再渲染Card */} {countries.length > 0 ? ( <Card className='country-cards'> <Card.Img variant='top' src={countries[0].image} /> <Card.Body> <Card.Title>{countries[0].name}</Card.Title> </Card.Body> </Card> ) : ( // 数据加载时显示提示 <div>加载中...</div> )} </div> </div> ); };
额外说明
- 用
map替代forEach转换数据,更简洁高效,直接生成新数组传给setCountries。 - 增加错误捕获,处理API请求失败的情况。
- 渲染时通过
countries.length > 0判断,避免数据未加载完成时访问undefined属性,同时给用户加载提示。
内容的提问来源于stack exchange,提问作者Fernando
相关产品推荐
相关产品推荐

