React项目中从对象/数组获取图标时遇undefined读取报错
解决React中"Cannot read properties of undefined (reading '0')"报错问题
问题场景
开发React天气项目时,尝试从OpenWeatherMap API返回的数据中提取图标路径,存入变量后作为props传递给子组件<Weather>,但页面触发报错:Cannot read properties of undefined (reading '0'),仅在使用<img src={props.icon} alt="cloud" />时出现,移除该标签后页面恢复正常。
报错原因
- 初始状态不匹配:
data的初始值设为[](数组),但API返回的是单个对象,导致初始渲染时data.weather为undefined,访问data.weather[0]直接报错。 - 无边界判断:在组件渲染阶段直接执行
data.weather[0].icon,未考虑API请求未完成、请求失败或返回数据异常的情况,此时data.weather可能不存在。 - 空值渲染风险:子组件中直接渲染
props.showItems.name,未做空值判断,也会在数据未返回时引发报错。
解决方案
- 修正初始状态:将
data的初始值改为空对象{},匹配API返回的数据结构。 - 添加空值保护:使用可选链操作符
?.或条件判断,确保在data.weather存在时再访问数组元素。 - 优化请求逻辑:避免在
search为空时发起无效请求,减少不必要的错误。 - 子组件空值处理:对所有从props接收的数据添加空值判断,确保安全渲染。
修改后的代码
App.js
import React, { useEffect, useState } from "react"; import Weather from "./components/Weather"; import "./App.css"; function App() { const [search, setSearch] = useState(""); const [data, setData] = useState({}); // 初始值改为空对象 useEffect(() => { // 仅当search不为空时发起请求 if (!search) return; fetch( `https://api.openweathermap.org/data/2.5/weather?q=${search}&appid=1769e69d20183ccd0c32ac3215db1d40&units=metric` ) .then((response) => response.json()) .then((json) => setData(json)) .catch((error) => { console.error(error); setData({}); // 请求失败时重置data }); }, [search]); const handleInput = (event) => { setSearch(event.target.value); }; // 使用可选链安全提取图标,不存在时返回空字符串 let icon = data?.weather?.[0]?.icon ? `${data.weather[0].icon}.png` : ""; return ( <div> <Weather icon={icon} inputValue={handleInput} showItems={data} /> </div> ); } export default App;
Weather.js
import "./style/Weather.css"; import "@fortawesome/fontawesome-free/css/all.css"; function Weather(props) { return ( <div className="container"> <div className="weather-container"> <input onChange={props.inputValue} type="text" placeholder="Enter a city name" /> {/* 添加空值判断,避免渲染undefined */} {props.showItems.name && <p>{props.showItems.name}</p>} {/* 仅当icon有值时渲染img标签 */} {props.icon && <img src={props.icon} alt="weather icon" />} {props.showItems.main && <p>{props.showItems.main.temp.toFixed()}°C</p>} </div> </div> ); } export default Weather;
内容的提问来源于stack exchange,提问作者Mirza Šabanović
相关产品推荐
相关产品推荐

