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

React天气应用报错TypeError: forcastWeather.list is undefined求助

天气应用API调用后页面空白问题排查与修复

问题描述

我是JavaScript和React新手,正在开发一款兼具当前天气与未来天气预报功能的应用。首次保存页面时,两次API调用均可正常展示数据,但切换页面或刷新后再次操作,页面会变为空白。在Firefox中检测到报错:Uncaught TypeError: forcastWeather.list is undefined。相关代码如下:

import {React, useState} from "react"
import './weather.css'


const Weather = () => {
    
    const apiKey = 'obsured-so-that-no-one-uses-my-key'
    const [weatherData, setWeatherData] = useState([{}])
    const [city, setCity] = useState("")
    const [forcastWeather, setForcastWeather] = useState([{}])
    
    const getWeather = (event) => {
        if (event.key === "Enter") {
            {fetch(`http://api.openweathermap.org/data/2.5/forecast?q=${city}&appid=${apiKey}&units=metric`)
            .then(response => response.json()).then(data => {setForcastWeather(data)})}
            {fetch(`https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}&units=metric`)
            .then(response => response.json()).then(data => {setWeatherData(data)})}
        }
    }
        

    return (
        <>
            <div className="container-about-weather">
                <input className="input-about-weather" 
                placeholder="Search"
                onChange={e => setCity(e.target.value)}
                value={city}
                onKeyPress={getWeather}>
                </input>
                <div>
                    {typeof weatherData.main === 'undefined' ? (
                        <div className="weather-content-rows-beginning">
                            <p>Welcome to my weather app. Enter a city name
                                to get the weather for that city
                            </p>
                        </div>
                    ) : (
                        <div className="weather-all">    
                            <div className="weather-now">
                                <div className="weather-content-rows-name">
                                    <p>{weatherData.name}, {weatherData.sys.country}</p>
                                </div>
                                <div className="weather-content-rows-temp">
                                    <p>{Math.round(weatherData.main.temp)}°C</p>
                                    <img src={`https://openweathermap.org/img/wn/${weatherData.weather[0].icon}@2x.png`} 
                                    alt=""/>
                                </div>
                                <div className="weather-content-rows-description">
                                    <p>{weatherData.weather[0].description}</p>
                                </div>
                                <div className="weather-content-humidity">
                                    <p>Humidity: {weatherData.main.humidity}</p>
                                </div>
                                <div className="weather-content-wind">
                                    <p>Wind: {(weatherData.wind.speed * 2.23694).toFixed(1)} mph</p>
                                </div>
                            </div>
                            <div className="weather-forcast">
                                <div className="weather-forcast-days">
                                    <img src={`https://openweathermap.org/img/wn/${forcastWeather.list[5].weather[0].icon}@2x.png`}></img>
                                    <p className="weather-forcast-days-text">{forcastWeather.list[5].main.temp}</p>
                                </div>
                            </div>
                        </div>
                    )}
                </div>
            </div>
        </>
    )
}


export default Weather

错误原因分析

  1. 初始状态类型不匹配:forcastWeather和weatherData初始值设为[{}](数组),但OpenWeatherMap API返回的是单个对象,初始状态下forcastWeather.list不存在,直接访问forcastWeather.list[5]会触发TypeError。
  2. 状态判断逻辑缺失:仅判断weatherData.main是否存在,未同步检查forcastWeather.list的加载状态。当weatherData加载完成但forcastWeather未返回数据时,会直接渲染天气预报部分导致报错。
  3. 混合内容拦截:天气预报API使用http协议,若页面在https环境下运行,浏览器会拦截该请求,导致forcastWeather无法获取数据,始终保持初始状态。

修复方案

1. 修正初始状态类型

将weatherData和forcastWeather的初始值改为空对象{},匹配API返回的数据结构:

const [weatherData, setWeatherData] = useState({})
const [forcastWeather, setForcastWeather] = useState({})

2. 完善状态判断逻辑

在渲染天气内容前,同时检查两个API的返回数据是否就绪:

{typeof weatherData.main === 'undefined' || typeof forcastWeather.list === 'undefined' ? (
    <div className="weather-content-rows-beginning">
        <p>Welcome to my weather app. Enter a city name to get the weather for that city</p>
    </div>
) : (
    // 渲染天气内容
)}

3. 统一API请求协议

将天气预报API的URL改为https,避免混合内容拦截:

fetch(`https://api.openweathermap.org/data/2.5/forecast?q=${city}&appid=${apiKey}&units=metric`)

4. 可选:添加错误捕获处理

捕获API请求失败的情况,避免异常数据导致渲染错误:

const getWeather = (event) => {
    if (event.key === "Enter") {
        fetch(`https://api.openweathermap.org/data/2.5/forecast?q=${city}&appid=${apiKey}&units=metric`)
            .then(response => {
                if (!response.ok) throw new Error('Forecast request failed');
                return response.json();
            })
            .then(data => setForcastWeather(data))
            .catch(err => console.error(err));

        fetch(`https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}&units=metric`)
            .then(response => {
                if (!response.ok) throw new Error('Current weather request failed');
                return response.json();
            })
            .then(data => setWeatherData(data))
            .catch(err => console.error(err));
    }
}

修改后的完整代码

import {React, useState} from "react"
import './weather.css'

const Weather = () => {
    const apiKey = 'obsured-so-that-no-one-uses-my-key'
    const [weatherData, setWeatherData] = useState({})
    const [city, setCity] = useState("")
    const [forcastWeather, setForcastWeather] = useState({})
    
    const getWeather = (event) => {
        if (event.key === "Enter") {
            fetch(`https://api.openweathermap.org/data/2.5/forecast?q=${city}&appid=${apiKey}&units=metric`)
                .then(response => {
                    if (!response.ok) throw new Error('Forecast request failed');
                    return response.json();
                })
                .then(data => setForcastWeather(data))
                .catch(err => console.error(err));

            fetch(`https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}&units=metric`)
                .then(response => {
                    if (!response.ok) throw new Error('Current weather request failed');
                    return response.json();
                })
                .then(data => setWeatherData(data))
                .catch(err => console.error(err));
        }
    }

    return (
        <>
            <div className="container-about-weather">
                <input 
                    className="input-about-weather" 
                    placeholder="Search"
                    onChange={e => setCity(e.target.value)}
                    value={city}
                    onKeyPress={getWeather}
                />
                <div>
                    {typeof weatherData.main === 'undefined' || typeof forcastWeather.list === 'undefined' ? (
                        <div className="weather-content-rows-beginning">
                            <p>Welcome to my weather app. Enter a city name to get the weather for that city</p>
                        </div>
                    ) : (
                        <div className="weather-all">    
                            <div className="weather-now">
                                <div className="weather-content-rows-name">
                                    <p>{weatherData.name}, {weatherData.sys.country}</p>
                                </div>
                                <div className="weather-content-rows-temp">
                                    <p>{Math.round(weatherData.main.temp)}°C</p>
                                    <img 
                                        src={`https://openweathermap.org/img/wn/${weatherData.weather[0].icon}@2x.png`} 
                                        alt={weatherData.weather[0].description}
                                    />
                                </div>
                                <div className="weather-content-rows-description">
                                    <p>{weatherData.weather[0].description}</p>
                                </div>
                                <div className="weather-content-humidity">
                                    <p>Humidity: {weatherData.main.humidity}%</p>
                                </div>
                                <div className="weather-content-wind">
                                    <p>Wind: {(weatherData.wind.speed * 2.23694).toFixed(1)} mph</p>
                                </div>
                            </div>
                            <div className="weather-forcast">
                                <div className="weather-forcast-days">
                                    <img 
                                        src={`https://openweathermap.org/img/wn/${forcastWeather.list[5].weather[0].icon}@2x.png`}
                                        alt={forcastWeather.list[5].weather[0].description}
                                    />
                                    <p className="weather-forcast-days-text">{Math.round(forcastWeather.list[5].main.temp)}°C</p>
                                </div>
                            </div>
                        </div>
                    )}
                </div>
            </div>
        </>
    )
}

export default Weather

内容的提问来源于stack exchange,提问作者Connor Dwyer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 07:36:17