TypeError: forcastWeather.列表未定义



我对javascript和react相当陌生,但我正在尝试构建这个天气应用程序,包括当前和未来的天气。

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

当我保存页面时,我似乎要进行第一个api调用和第二个api调用(显示信息)。但是,当我切换页面或重新加载并再次尝试时,页面将变为空白,直到重新加载为止。我在火狐浏览器中发现了一个错误,上面写着"Uncaught TypeError: forcastWeather"。列表未定义"我希望这对你有帮助

我知道这可能是模糊的,但我想知道是否有人可以帮助我?

总的来说,你可以添加一些有帮助的改进!对于初学者,您有两个异步函数—

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

但是在你的渲染中,你基于你的决定"我有天气数据吗";仅基于第一个函数的结果-

{typeof weatherData.main === 'undefined' ? (...) : (...)}

如果第一个异步函数通过,但第二个失败了会发生什么?或者,如果第二个异步函数完成得比第一个慢得多怎么办?

解决这个问题的一个简单方法是创建一个显式的布尔值来检查两个异步调用是否已经完成,在渲染之前;比如:

const hasWeatherData = !!(weatherData.main && forcastWeather.list?.length > 0);
return (
<>
{!hasWeatherData && (...)}
{hasWeatherData && (...)}
</>
);

这不是一个完美的解决方案!它仍然不能满足其中一个调用失败,或者您的其他假设之一失败(例如,如果forcastWeather.list中只有3个元素怎么办?那么forcastWeather.list[5].main.temp将失败)。

因此,另一个想法是将组件分解为具有较小职责的较小组件。例如,您可以打开"预测"。部件变成更小的部件:

const WeatherForecast = ({ forecastWeather }) => {
const forecast = forecastWeather?.list?.length > 5
? forecastWeather.list[5]
: undefined;
if (!forecast) {
return (
<div>Forecast weather not found</div>
);
}
return (
<div className="weather-forcast">
<div className="weather-forcast-days">
<img src={`https://openweathermap.org/img/wn/${forecast.weather[0].icon}@2x.png`}></img>
<p className="weather-forcast-days-text">{forecast.main.temp}</p>
</div>
</div>        
);
}

然后从父组件调用-

return (
<>
{/* ----- 8< ----- */}
<WeatherForecast forecastWeather={forecastWeather} />
</>
);

页面变黑的原因是数据不再存在,因为您手动调用它们,为了避免此类错误,您需要处理这些数据不可用的情况。

最新更新