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

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>
    )
}

错误原因

  1. 异步请求时序问题:useEffect确实会在组件首次渲染后执行,但API请求是异步操作——组件首次渲染时,请求还未返回结果,此时data.current是空数组,data.current[0]为undefined,访问.image就会抛出"无法读取undefined的image属性"的错误。
  2. 状态存储工具误用:useRef的更新不会触发组件重新渲染,就算API请求完成后data.current有了数据,组件也不会重新渲染展示新内容,这类需要驱动视图更新的数据应该用useState管理。
  3. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 11:15:45