React项目API数据控制台可见但页面不渲染,报weather、wind未定义
问题描述
我已经花了好几个小时尝试解决这个问题,但一直没成功。API返回的数据能在控制台正常显示,但就是没法在浏览器页面上渲染出来,我不确定是不是代码哪里出错了,下面是我的代码,麻烦帮忙排查一下。
import React, { useState, useEffect } from "react"; import "../Componentstyle/Main.css"; export default function Maindata() { const [data, setData] = useState(null); let weather = async () => { const key = "1ab6ef20384db1d7d9d205d609f7eef0"; await fetch( `https://api.openweathermap.org/data/2.5/weather?q=dubai&appid=${key}&units=metric&formatted=0` ) .then((response) => response.json()) .then((actualData)=> setData(actualData)); }; useEffect(() => { weather() }, []); const link = `http://openweathermap.org/img/w/${data.weather[0].icon}.png` return ( <div className="maindata"> <div className="city">{data.name}</div> <div className="temp">{data.main.temp} C</div> <div className="icon"><img src={link} alt="not found" /> </div> <div className="feel">feels Like {data.main.feels_like} C</div> <div className="wind">Wind {data.wind.speed} Km/hr</div> <div className="cloudy">{data.weather[0].main}</div> <div className="humidity">humidity {data.main.humidity}%</div> <div className="sunrise">sunrise :- {(new Date((data.sys.sunrise)*1000).toUTCString())} </div> <div className="sunset">sunset :- {new Date(data.sys.sunset*1000).toUTCString()}</div> </div> ); }
问题排查与修复
核心问题
组件初始化时data的初始值是null,第一次渲染时直接访问data.weather[0].icon、data.name等属性会触发Cannot read properties of null的错误,导致组件崩溃无法渲染。而控制台能看到数据是因为后续API请求完成后data被更新,但此时组件已经报错停止渲染了。
修复方案
方案1:添加加载与错误状态判断(推荐)
通过加载状态控制渲染流程,避免在数据未准备好时访问属性,同时增加错误处理:
import React, { useState, useEffect } from "react"; import "../Componentstyle/Main.css"; export default function Maindata() { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const weather = async () => { try { const key = "1ab6ef20384db1d7d9d205d609f7eef0"; const response = await fetch( `https://api.openweathermap.org/data/2.5/weather?q=dubai&appid=${key}&units=metric&formatted=0` ); if (!response.ok) throw new Error('天气数据请求失败'); const actualData = await response.json(); setData(actualData); } catch (err) { setError(err.message); } finally { setLoading(false); } }; useEffect(() => { weather(); }, []); // 加载中状态 if (loading) return <div>加载天气数据中...</div>; // 错误状态 if (error) return <div>出错了:{error}</div>; // 无数据兜底 if (!data) return <div>未获取到天气数据</div>; const link = `http://openweathermap.org/img/w/${data.weather[0].icon}.png`; return ( <div className="maindata"> <div className="city">{data.name}</div> <div className="temp">{data.main.temp}℃</div> <div className="icon"><img src={link} alt="天气图标" /></div> <div className="feel">体感温度 {data.main.feels_like}℃</div> <div className="wind">风速 {data.wind.speed} Km/hr</div> <div className="cloudy">{data.weather[0].main}</div> <div className="humidity">湿度 {data.main.humidity}%</div> <div className="sunrise">日出时间:{new Date(data.sys.sunrise * 1000).toUTCString()}</div> <div className="sunset">日落时间:{new Date(data.sys.sunset * 1000).toUTCString()}</div> </div> ); }
方案2:使用可选链操作符兜底
如果不想添加加载状态,可以用可选链?.避免访问null属性报错,但这种方式会在数据加载前显示空内容:
// 修改链接生成逻辑 const link = data?.weather?.[0]?.icon ? `http://openweathermap.org/img/w/${data.weather[0].icon}.png` : ''; // 渲染部分的每个属性都添加可选链 return ( <div className="maindata"> <div className="city">{data?.name}</div> <div className="temp">{data?.main?.temp}℃</div> <div className="icon"><img src={link} alt="天气图标" /></div> <div className="feel">体感温度 {data?.main?.feels_like}℃</div> <div className="wind">风速 {data?.wind?.speed} Km/hr</div> <div className="cloudy">{data?.weather?.[0]?.main}</div> <div className="humidity">湿度 {data?.main?.humidity}%</div> <div className="sunrise">日出时间:{data?.sys?.sunrise ? new Date(data.sys.sunrise * 1000).toUTCString() : ''}</div> <div className="sunset">日落时间:{data?.sys?.sunset ? new Date(data.sys.sunset * 1000).toUTCString() : ''}</div> </div> );
额外优化点
- 移除
async/await与then的混用,统一用await写法更清晰易读 - 添加API请求错误处理,避免请求失败时组件崩溃
- 中文环境下把温度单位改为
℃更符合用户习惯
内容的提问来源于stack exchange,提问作者Ahsan Khalid
相关产品推荐
相关产品推荐

