作为学习 React 的一个副项目,我选择制作一个天气应用。为此,我使用了 OpenWeatherMap API,并选择了 One Call API 和 Geocoding API。我遇到的问题是,当我想呈现 JSON 响应时,出现错误:TypeError: Cannot read property 'temp' of undefined
。在他们的文档 (OpenWeatherMap One Call API Docs) 中,我需要用于温度的对象似乎是 current.temp
,但它不起作用。
Forecast.js
function getForecast(e) {
e.preventDefault();
if (city.length === 0) {
return setError(true);
}
// Clear state in preparation for new data
setError(false);
setResponseObj({});
setLoading(true);
const uriEncodedCity = encodeURIComponent(city);
let KEY = process.env.REACT_APP_API_KEY
const geoCoding = fetch(`http://api.openweathermap.org/geo/1.0/direct?q=${uriEncodedCity}&limit=1&appid=${KEY}`, {
"method": "GET"
})
.then(responseGeo => responseGeo.json())
geoCoding.then(apiCall => {
return fetch(`https://api.openweathermap.org/data/2.5/onecall?lat=${apiCall[0].lat}&lon=${apiCall[0].lon}&units=${unit}&appid=${KEY}`)
})
.then(response => response.json())
.then(response => {
setResponseObj(response);
setLoading(false);
})
.catch(err => {
setError(true);
setLoading(false);
console.log(err.message);
});
}
Conditions.js
const conditions = (props) => {
return (
<div className={classes.Wrapper}>
{
props.error && <small className={classes.Small} > Please enter a valid city. </small>}
{
props.loading && < div className={classes.Loader} />}
{
<div className={classes.information}>
{/* <h1 className={classes.location}><strong>{props.responseObj.name}, {props.responseObj.sys.country} </strong></h1>
<p className={classes.title} ><img className="card-img-top" src={`http://openweathermap.org/img/wn/${props.responseObj.weather[0].icon}@2x.png`} alt="weather icon" style={{ width: 130, height: 130 }} /></p> */}
<p className={classes.title} >{Math.round(props.responseObj.current.temp)}° with {props.responseObj.current.weather[0].description}. </p>
{<p className={classes.info}>{clothes(props.unit, Math.round(props.responseObj.current.temp))}</p>}
<p className={classes.info}>{rain(props.responseObj.current.weather[0].description)}</p>
<p className={classes.info}><img src={Thermo} alt="feels like icon" style={{ width: 50, height: 50 }} /> Feels like: <b>{(props.responseObj.current.feels_like).toFixed()}° </b></p>
<p className={classes.info}><img src={Atmoshperic} alt="atmospheric icon" style={{ width: 50, marginRight: 5, height: 50 }} /> Atmoshperic Pressure: <b>{props.responseObj.current.pressure}hPa</b></p>
<p className={classes.info}><img src={Humidity} alt="humidity icon" style={{ width: 50, marginRight: 5, height: 50 }} /> Humidity: <b>{props.responseObj.current.humidity}%</b></p>
<p className={classes.info}><img src={Cloudy} alt="cloudy icon" style={{ width: 50, height: 50 }} /> Cloudiness: <b>{(props.responseObj.current.clouds)}% </b></p>
<p className={classes.info}><img src={Wind} alt="wind icon" style={{ width: 50, marginRight: 5, height: 50 }} /> Wind: <b>{props.responseObj.current.wind_speed} m/s, {compassSector[(props.responseObj.current.wind_deg / 22.5).toFixed(0)]} </b> <img src={Arrow} alt="windarrow" style={{ width: 14, transform: `rotate(${props.responseObj.current.wind_deg}deg)`, height: 14 }} /></p>
<p className={classes.info}><img src={Sunrise} alt="sunrise icon" style={{ width: 50, marginRight: 5, height: 50 }} /> Sunrise is at: <b>{moment.unix(props.responseObj.current.sunrise).format('HH:mm')} </b></p>
<p className={classes.info}> <img src={Sunset} alt="sunset icon" style={{ width: 50, marginRight: 5, height: 50 }} />Sunset is at: <b>{moment.unix(props.responseObj.current.sunset).format('HH:mm')}</b></p>
</div >
} </div>
)
}
示例:
{
"lat":47.1667,
"lon":27.6,
"timezone":"Europe/Bucharest",
"timezone_offset":10800,
"current":{
"dt":1627819113,
"sunrise":1627786102,
"sunset":1627839801,
"temp":86.52,
...
}
如果我使用 props.responseObj.lat
或 props.responseObj.lon
,我不会出错,但如果我尝试使用 props.responseObj.current.temp
,我会收到 TypeError: Cannot read property 'temp' of undefined
错误。
答案 0 :(得分:2)
看起来您正在访问初始渲染时未定义的属性。
Forecast
中,初始 responseObj
状态为空对象,而 loading
状态初始为假。{}
responseObj
值被传递给 Conditions
。Conditions
尝试访问 props.responseObj.current.XXXX
。props
是 OFC 定义的,props.responseObj
也是如此,值为 {}
。下一段 props.responseObj.current
未定义。在您尝试访问未定义值的 temp
之前,这本身并不是问题。
注意:这可能在调用 getForecast
的任何时候发生,因为它会将 responseObj
状态重置回空对象 ({}
)。
如果 props.responseObj
属性存在,您应该有条件地呈现 current
数据。
const conditions = (props) => {
return (
<div className={classes.Wrapper}>
{props.error && (
<small className={classes.Small}> Please enter a valid city. </small>
)}
{props.loading && <div className={classes.Loader} />}
{props.responseObj.current && (
<div className={classes.information}>
<p className={classes.title}>
{Math.round(props.responseObj.current.temp)}° with{" "}
{props.responseObj.current.weather[0].description}.{" "}
</p>
{
<p className={classes.info}>
{clothes(props.unit, Math.round(props.responseObj.current.temp))}
</p>
}
<p className={classes.info}>
{rain(props.responseObj.current.weather[0].description)}
</p>
<p className={classes.info}>
<img
src={Thermo}
alt="feels like icon"
style={{ width: 50, height: 50 }}
/>{" "}
Feels like:{" "}
<b>{props.responseObj.current.feels_like.toFixed()}° </b>
</p>
<p className={classes.info}>
<img
src={Atmoshperic}
alt="atmospheric icon"
style={{ width: 50, marginRight: 5, height: 50 }}
/>{" "}
Atmoshperic Pressure: <b>{props.responseObj.current.pressure}hPa</b>
</p>
<p className={classes.info}>
<img
src={Humidity}
alt="humidity icon"
style={{ width: 50, marginRight: 5, height: 50 }}
/>{" "}
Humidity: <b>{props.responseObj.current.humidity}%</b>
</p>
<p className={classes.info}>
<img
src={Cloudy}
alt="cloudy icon"
style={{ width: 50, height: 50 }}
/>{" "}
Cloudiness: <b>{props.responseObj.current.clouds}% </b>
</p>
<p className={classes.info}>
<img
src={Wind}
alt="wind icon"
style={{ width: 50, marginRight: 5, height: 50 }}
/>{" "}
Wind:{" "}
<b>
{props.responseObj.current.wind_speed} m/s,{" "}
{
compassSector[
(props.responseObj.current.wind_deg / 22.5).toFixed(0)
]
}{" "}
</b>{" "}
<img
src={Arrow}
alt="windarrow"
style={{
width: 14,
transform: `rotate(${props.responseObj.current.wind_deg}deg)`,
height: 14
}}
/>
</p>
<p className={classes.info}>
<img
src={Sunrise}
alt="sunrise icon"
style={{ width: 50, marginRight: 5, height: 50 }}
/>{" "}
Sunrise is at:{" "}
<b>
{moment.unix(props.responseObj.current.sunrise).format("HH:mm")}{" "}
</b>
</p>
<p className={classes.info}>
{" "}
<img
src={Sunset}
alt="sunset icon"
style={{ width: 50, marginRight: 5, height: 50 }}
/>
Sunset is at:{" "}
<b>
{moment.unix(props.responseObj.current.sunset).format("HH:mm")}
</b>
</p>
</div>
)}
</div>
);
};
您还可以对加载状态使用三元运算符。
{props.loading ? (
<div className={classes.Loader} />
) : (
<div className={classes.Wrapper}>
.....
</div>
)}
或者在所有访问中使用可选链操作符。
const conditions = (props) => {
return (
<div className={classes.Wrapper}>
{props.error && (
<small className={classes.Small}> Please enter a valid city. </small>
)}
{props.loading && <div className={classes.Loader} />}
<div className={classes.information}>
<p className={classes.title}>
{Math.round(props.responseObj.current?.temp)}° with{" "} // <-- Optional Chaining
{props.responseObj.current?.weather[0].description}.{" "} // <-- Optional Chaining
</p>
{
<p className={classes.info}>
{clothes(props.unit, Math.round(props.responseObj.current?.temp))} // <-- Optional Chaining
</p>
}
<p className={classes.info}>
{rain(props.responseObj.current?.weather[0].description)} // <-- Optional Chaining
</p>
...... etc....
</div>
</div>
);
};