arrays - 使数组渲染等待 axios 调用
问题描述
我的目的是获取所选国家的天气数据,将 selectedCountry.capital 传递给查询,因此在显示国家数据时会显示当前国家首都的天气。
问题是我的代码尝试在获取天气数组之前呈现天气数据,从而导致错误。
TypeError:无法读取未定义的属性“温度”
我得到数组数据
useEffect(() => {
if( selectedCountry.capital !== '' )
{
axios
.get(
`http://api.weatherstack.com/current?access_key=b51dfd70b0b2ccf136a0d7352876661c&query=${selectedCountry.capital}`
)
.then(res =>{
console.log(res.data)
console.log("capital" +selectedCountry.capital)
setWeather(res.data.current)
} )
}
}, [selectedCountry.capital])
渲染它
<div>
<h4>Weather</h4>
<h5>temperature: {weather.temperature} Celisues</h5>
<img src={weather.weather_icons[0]} alt='' />
<h5>
wind: {weather.wind_degree} mph direction {weather.wind_dir}
</h5>
</div>
i 如果我不渲染数组,我可以将天气数据很好地发送到控制台。此外,如果我在数组已经存在时添加数组渲染代码,天气数据会正确显示。
使数组渲染等待从 axios 调用中获取数组的最佳方法是什么?
import React, { useState, useEffect } from 'react'
import axios from 'axios'
//setCountries is a function for setting the country's state
const App = () => {
const [countries, setCountries] = useState([])
//Filter
const [searchFilter, setSearchFilter] = useState('')
//Update state with button
const [selectedCountry, setSelectedCountry] = useState('')
const [weather, setWeather] = useState('')
const hook = () => {
console.log('effect')
axios
.get('https://restcountries.eu/rest/v2/all')
.then(response => {
console.log('promise fulfilled')
setCountries(response.data)
})
}
useEffect(hook,[])
/* by default the effect is always run after the component has been rendered. In our case, however, we only want to execute the effect along with the first render.
The second parameter of useEffect is used to specify how often the effect is run. If the second parameter is an empty array [], then the effect is only run along with the first render of the component. */
console.log('render', countries.length, 'countries')
console.log(countries)
/* weather */
useEffect(() => {
if( selectedCountry.capital !== '' )
{
axios
.get(
`http://api.weatherstack.com/current?access_key=b51dfd70b0b2ccf136a0d7352876661c&query=${selectedCountry.capital}`
)
.then(res =>{
console.log(res.data)
console.log("capital" +selectedCountry.capital)
setWeather(res.data.current)
} )
}
}, [selectedCountry.capital])
//When button es clicked the state is set, and the state variable is used
const renderCountryDetails = () => {
return (
selectedCountry && (
<p key={selectedCountry.alpha2Code}>
<p> Capital: {selectedCountry.capital}.</p>
<p> Population:{" "}
{selectedCountry.population}</p>
<p>
<img src={selectedCountry.flag} style={{ width: '200px'}}/>
</p>
<h3>Languages</h3>
<p> {selectedCountry.languages.map(language => <li key={language.name}>{language.name}</li>)}
<div>
<h4>Weather</h4>
<h5>temperature: {weather.temperature} Celisues</h5>
<img src={weather.weather_icons[0]} alt='' />
<h5>
wind: {weather.wind_degree} mph direction {weather.wind_dir}
</h5>
</div>
</p>
</p>
)
);
};
const filteredCountries =
searchFilter.length === 1
? countries
: countries.filter(
(country) => country.name.toLowerCase().indexOf(searchFilter.toLowerCase()) > -1
)
//showCountries returns either a message or else the contents of filteredcountries array
const showCountries = () => {
if (filteredCountries.length > 10) {
return 'Too many matches, keep on typing'
}
if (filteredCountries.length > 0
&& filteredCountries.length<10
&& filteredCountries.length>1 )
{
return (
<div>
{filteredCountries.map((country) => (
<p key={country.alpha2Code}>
{country.name}
{
//Update stste when button is clicked, passing country as a prop to the state
//onClick state is updated, causing the page to refresh and executing renderCountryDetails
//that uses the set state (the country) to render the info.
<button onClick={
() => setSelectedCountry(country)}>
show
</button>
}
</p>
))}
<div>{renderCountryDetails()}</div>
<div>
<p></p>
</div>
</div>
);
}
if (filteredCountries.length === 1) {
return filteredCountries.map((country) =>
<p key={country.alpha2Code}>
<p>Capital: {country.capital}.
<p> Population: {country.population} </p>
<h3>languages</h3>
{country.languages.map(language => <li key={language.name}>{language.name}</li>)}
<p><img src={country.flag} style={{ width: '200px'}}/>
</p>
</p>
</p>
)
}
}
const searchHandler = (e) => {
//setSelectedCountry state is set to empty
setSelectedCountry("");
setSearchFilter(e.target.value)
}
return (
<div>
<div>
<h1>Countries</h1>
</div>
<div>
Type to find countries:
<input onChange={searchHandler} />
<div>
{showCountries()}
</div>
</div>
</div>
);
}
export default App;
解决方案
只需在此处使用可选链接:
<h5>temperature: {weather?.temperature||""} Celisues</h5>
在这种情况下,如果温度未定义,它不会抱怨,而是会呈现一个空字符串。
"" 可以替换为在从 API 获取数据时您需要显示的任何默认值,例如 0 或其他内容。
更多关于可选链接的信息:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining
推荐阅读
- powerbi - 单击图表信息时如何重定向
- java - 使用没有 JsonSubTypes 的杰克逊将接口反序列化为特定类型
- spring - 使用没有类型的 args 指示符创建切入点会导致 BeanCurrentlyInCreationException
- python-3.x - len 和输出有什么问题
- python - OpenCV 打开带有 URL 的图像
- awk - 提取遵循模式的行
- python-3.x - 根据熊猫中的某些条件过滤数据框的行
- google-apps-script - 通过 Apps 脚本删除经典 Google 协作平台页面
- python - 如果字符串中的字符将转义字符“\”放在找到的字符前面
- reactjs - 当我编译 index.js 文件时,React 不会刷新 Chrome 和 Firefox 中的页面