尝试使用useEffect钩子从api获取数据时发生React错误



我正试图使用一个api创建一个简单的天气web应用程序,该应用程序包含一个搜索城市和显示信息的输入表单。我想使用useEffect挂钩将默认城市设置为特定城市。因此,用户一打开应用程序,就会显示有关该市天气的信息。但是,它会返回一个错误,表示不存在类似的数据。

这是我的App.js文件

import React, { useState, useEffect } from 'react'
import Search from './components/Search.js'
import './App.scss';
function App() {
const [city, setCity] = useState('London')
const [unit, setUnit] = useState('metric')
const [info, setInfo] = useState({})
const key = process.env.REACT_APP_WEATHER_API_KEY
const api = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${key}&units=${unit}`
useEffect(() => {
fetch(api)
.then(res => {
if (!res.ok){
throw Error('could not fetch the data')
} 
return res.json()
})
.then(data => {
setInfo(data)
console.log(data)
})
.catch(err => console.log(err.message))
}, [city])  

return (
<div className="app">
<Search setCity={setCity}/> 
<h1 className='city'>{city}</h1>
<h2 className='temperature'>Temperature: {info.main.temp}</h2>
</div>
);
}
export default App;

Search.js文件

import React from 'react'
function Search({setCity}) {
const search = (e) => {
const loc = e.target.value.trim().replace(/^w/, (c) => c.toUpperCase())
if (e.key === 'Enter' && loc !== ''){
setCity(loc)
}
}
return (
<div className='search-container'>
<input type="text" onKeyPress={search} defaultValue='London'/>
</div>
)
}
export default Search

错误消息

Uncaught TypeError: Cannot read properties of undefined (reading 'temp')

这个错误似乎是因为我试图访问h2标签中的温度信息(info.main.temp(而发生的。但是,如果我删除它,一切都会正常工作,并且信息仍然会从api中检索到。

您已将info初始化为空对象-

const [info, setInfo] = useState({})

组件第一次渲染时,info对象上没有main属性(因为它是空的(,所以此调用总是失败,并显示错误:

<h2 className='temperature'>Temperature: {info.main.temp}</h2>

要修复它,您可以在使用可选链接访问之前检查属性是否存在:

<h2 className='temperature'>Temperature: {info.main?.temp}</h2>

您的使用效果取决于"城市";。一开始,你试图在任何城市变化之前显示温度值。

为了解决这个问题,你可以避免尝试显示标签:

{info && <h2 className='temperature'>Temperature: {info.main.temp}</h2>}

或:

{info ? <h2 className='temperature'>Temperature: {info.main.temp}</h2> : <Loading/>}

在这种情况下,您不需要将默认值设置为"0";信息";useState。

const [info, setInfo] = useState()

如果您检查info.main没有未定义,然后将其渲染出来,那将是更好的

import React, { useState, useEffect } from 'react'
import Search from './components/Search.js'
import './App.scss';
function App() {
const [city, setCity] = useState('London')
const [unit, setUnit] = useState('metric')
const [info, setInfo] = useState({})
const key = process.env.REACT_APP_WEATHER_API_KEY
const api = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${key}&units=${unit}`
useEffect(() => {
fetch(api)
.then(res => {
if (!res.ok){
throw Error('could not fetch the data')
} 
return res.json()
})
.then(data => {
setInfo(data)
console.log(data)
})
.catch(err => console.log(err.message))
}, [city])  

return (
<div className="app">
<Search setCity={setCity}/> 
<h1 className='city'>{city}</h1>
{info.main ? (
<h2 className='temperature'>Temperature: {info.main.temp}</h2>
) : (
<h2 className='loading'>Loading...</h2>
)}
</div>
);
}
export default App;

您可以为weather API创建一个接口,如下所示。

export interface Coord {
lon: number;
lat: number;
}
export interface Weather {
id: number;
main: string;
description: string;
icon: string;
}
export interface Main {
temp: number;
feels_like: number;
temp_min: number;
temp_max: number;
pressure: number;
humidity: number;
}
export interface Wind {
speed: number;
deg: number;
}
export interface Clouds {
all: number;
}
export interface Sys {
type: number;
id: number;
message: number;
country: string;
sunrise: number;
sunset: number;
}
export interface RootObject {
coord: Coord;
weather: Weather[];
base: string;
main: Main;
visibility: number;
wind: Wind;
clouds: Clouds;
dt: number;
sys: Sys;
timezone: number;
id: number;
name: string;
cod: number;
}
export interface IWeather {
coord: Coord;
weather: Weather;
base: string;
main: Main;
visibility: number;
wind: Wind;
clouds: Clouds;
dt: number;
sys: Sys;
timezone: number;
id: number;
name: string;
cod: number;
}

然后在App.tsx中,您需要修改两件事。

const [info, setInfo] = useState<IWeather | null>();

<h2 className="temperature">Temperature: {info?.main?.temp}</h2>

你可以查看工作演示

如果你有任何疑问,请告诉我。

您收到该错误只是因为您试图在从api 获取数据之前访问临时数据

只需添加空检查"在信息之后,无论何时尝试从信息访问数据,一旦从api 获得数据,它都会检查临时数据

并在声明时将信息状态声明为null

const [info, setInfo] = useState(null)

<h2 className='temperature'>Temperature: {info?.main.temp}</h2>

相关内容

  • 没有找到相关文章

最新更新