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

React中useEffect首次渲染数据为空,访问显示undefined求助

问题分析与解决方案

问题根源

  1. 初始State设置不当:你把初始state设为[{}],组件首次渲染时这个空对象里没有image、nativeName等属性,直接访问会抛出undefined错误。
  2. 条件判断逻辑失效:用data? ... : null判断时,data本身是数组(初始值[{}]为真值),判断逻辑不起作用,依然会访问不存在的属性。
  3. 数据访问路径错误:右侧信息区域里的data.topLevelDomain缺少数组索引,正确路径应为data[0].topLevelDomain。
  4. API数据硬编码风险:response.data[0].name.nativeName.nld里的nld是特定语种的键,并非所有国家都存在该字段,会导致请求失败,进而setData不执行,data始终停留在初始值。
  5. useEffect依赖缺失:依赖数组为空,但countryName是组件内计算的值,加入依赖能确保useEffect触发逻辑正确。

修复后的代码

import { useState, useEffect } from 'react';
import { Link } from 'react-router-dom';
import axios from 'axios';

const CountryInfo = () => {
    // 初始state设为空数组,便于判断加载状态
    const [data, setData] = useState([]);
    let countryName = window.location.pathname;

    countryName = countryName.replace('/', '');
    countryName = countryName.split('%20').join(' ');

    useEffect(() => {
        // 添加错误捕获,避免请求失败导致组件卡死
        axios.get(`https://restcountries.com/v3.1/name/${countryName}`)
            .then(response => {
                const countryData = response.data[0];
                // 动态获取nativeName,避免硬编码语种键
                const nativeName = countryData.name.nativeName 
                    ? Object.values(countryData.name.nativeName)[0].common 
                    : countryData.name.common;
                
                setData([{
                    name: countryName,
                    image: countryData.flags.png,
                    nativeName: nativeName,
                    population: countryData.population,
                    region: countryData.region,
                    subRegion: countryData.subregion,
                    capital: countryData.capital?.[0] || 'N/A', // 处理无首都的国家
                    borderCountries: countryData.borders || [],
                    topLevelDomain: countryData.tld?.[0] || 'N/A',
                    currencies: countryData.currencies 
                        ? Object.values(countryData.currencies)[0].name 
                        : 'N/A',
                    languages: countryData.languages 
                        ? Object.values(countryData.languages).join(', ') 
                        : 'N/A',
                }])
            })
            .catch(err => {
                console.error('获取国家数据失败:', err);
            });
    }, [countryName]); // 添加countryName到依赖数组,确保逻辑触发正确

    // 数据未加载时显示加载提示
    if (data.length === 0) {
        return <div>加载中...</div>;
    }

    // 提前解构数据,简化后续访问路径
    const country = data[0];

    return(
        <div className='country-info-content'>
            <Link to='/' className='info-button'>
                <button className='button-info'>BACK</button>
            </Link>
            <div className='data-info'>
                <img src={country.image} className='flag-img' alt={`${country.name}国旗`}/>
                <div className='country-name'>
                    <span className='name'>{country.name}</span>
                    <div className='info-description'>
                        <div>
                            <div>
                                <span>Native Name:</span> {country.nativeName}
                            </div>
                            <div>
                                <span className='title'>Population:</span> {country.population.toLocaleString(undefined)}
                            </div>
                            <div>
                                <span className='title'>Region:</span> {country.region}
                            </div>
                            <div>
                                <span className='title'>Sub Region:</span> {country.subRegion}
                            </div>
                            <div>
                                <span className='title'>Capital:</span> {country.capital}
                            </div>
                        </div>
                        <div className='right-info'>
                            <div>
                                <span className='title'>Top Level Domain:</span> {country.topLevelDomain}
                            </div>
                            <div>
                                <span className='title'>Currency:</span> {country.currencies}
                            </div>
                            <div>
                                <span className='title'>Languages:</span> {country.languages}
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    )
}

export default CountryInfo;

关键修改说明

  • 初始State改为空数组:通过data.length === 0判断数据是否加载完成,避免访问不存在的属性。
  • 添加错误处理:请求失败时打印错误,便于排查问题。
  • 处理API数据不确定性:用可选链?.和Object.values()处理可能不存在的字段,避免硬编码特定键名导致的错误。
  • 提前解构数据:在return前把data[0]赋值给country,简化后续代码的访问路径。
  • 完善条件渲染:数据未加载时显示加载提示,提升用户体验。
  • 修正useEffect依赖:加入countryName确保依赖逻辑正确。

内容的提问来源于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 18:39:21