我是React,JS,JSX的新手。
setNewWeather似乎没有正确更新天气状态,因为它是由初始值定义的,但是随后变为undefined。
因为它更新了,应该引起重新渲染;我看过很多关于此的文章,但他们建议喜欢,等待异步数据操作,但是据我了解,使用'.then'方法具有内在的功能吗? 还是涉及setNewWeather语法的另一个问题,例如它需要在内部使用一个函数而不只是一个字符串来更新状态?
我的代码:
import React, { useState, useEffect } from 'react'
import axios from 'axios'
const Header = ({ text }) => <h1>{text}</h1>
const Header3 = ({ text }) => <h3>{text}</h3>
const Image = ({ source, alttext }) => <img src={source} alt={alttext} />
const Button = ({ onClick, text }) => (<button onClick={onClick}>{text}</button>)
const ListItem = ({ item }) => <li>{item}</li>
const List = ({ title, stuff }) => {
return(
<>
< Header3 text={title} />
<ul>
{stuff.map((item, index) => < ListItem key={index} item={item} />)}
</ul>
</>)}
const Search = ({ text, value, onChange }) => {
return (
<>
{text}
<input value={value} onChange={onChange} />
</>)}
const CountryMany = ({ country, handleClick }) => {
return (
<>
<li>{country.name}</li>
< Button onClick={handleClick(country.name)} text='Show' />
</>)}
const CountryFound = ({ country, api_key, handleWeather, newWeather }) => {
const countryFound = country[0]
const params = {
access_key: api_key,
query: countryFound.capital
}
useEffect(() => {
axios.get('http://api.weatherstack.com/current', {params})
.then(response => {
console.log('RESPONSE', response.data)
handleWeather({ is: 'weather', data: response.data })
console.log(newWeather)
})},
[params, newWeather, handleWeather])
console.log('yo')
console.log(newWeather)
const languages = countryFound.languages.map(lang => lang.name)
return (
<>
< Header text={countryFound.name} />
<p>Capital: {countryFound.capital}</p>
<p>Population: {countryFound.population}</p>
< List title='Languages' stuff={languages} />
< Header3 text='Flag' />
< Image source={countryFound.flag} alttext='flag' />
< Header3 text='Weather' />
<ul>
<li>Temperature: {newWeather}</li>
<li> Image source= alttext=weather </li>
</ul></>)}
const Countries = (props) => {
console.log('COUNTRIES PROPS', props)
console.log('WEATHER', props.newWeather)
const countries = props.countries
const foundCountries = countries.filter(country =>
country.name.toLowerCase().includes(props.newSearch.toLowerCase()))
if (foundCountries.length > 10 ) {
return (<p>Too Many Matches, Keep Typing!</p>)}
if (foundCountries.length > 1) {
return (
<ul>
{foundCountries.map(country =>
< CountryMany key={country.population} country={country} handleClick={props.handleClick} />)}
</ul>)}
if (foundCountries.length === 1) {
return (
<>
<CountryFound api_key={props.a_k1} country={foundCountries}
handleWeather={props.handleWeather} weather={props.newWeather} />
</>)}
return (<></>)}
const App = () => {
const api_key = process.env.REACT_APP_API_KEY
const [ countries, setCountries ] = useState([])
const [ newSearch, setNewSearch ] = useState('')
const [ newWeather, setWeather ] = useState({ is: 'no ewather' })
const handleWeather = ( is, data ) => () => {
setWeather( is, data )
console.log('HEY HANDLEWEATHER', newWeather)}
useEffect(() => {
axios
.get('https://restcountries.eu/rest/v2/all')
.then(response => {
setCountries(response.data)
})}, [])
const handleClick = (value) => () => {
setNewSearch(value)}
const handleSearch = (event) => {
setNewSearch(event.target.value)}
return (
<div>
< Search text='Find A Country: ' value={newSearch} onChange={handleSearch}/>
< Countries countries={countries}
a_k1={api_key}
handleWeather={handleWeather}
handleClick={handleClick}
newSearch={newSearch}
newWeather={newWeather}
/>
</div>)}
export default App
/*
const Weather = ({ weather }) => {
return (
<>
< Header3 text='Weather' />
<ul>
<li>Temperature: weather.temperature</li>
<li> Image source= alttext=weather </li>
</ul>
</>)}
*/
谢谢!
编辑:状态正在更新,但只能通过形成无限循环来实现:
import React, { useState, useEffect } from 'react'
import axios from 'axios'
const Header = ({ text }) => <h1>{text}</h1>
const Header3 = ({ text }) => <h3>{text}</h3>
const Image = ({ source, alttext }) => <img src={source} alt={alttext} />
const Button = ({ onClick, text }) => (<button onClick={onClick}>{text}</button>)
const ListItem = ({ item }) => <li>{item}</li>
const List = ({ title, stuff }) => {
return(
<>
< Header3 text={title} />
<ul>
{stuff.map((item, index) => < ListItem key={index} item={item} />)}
</ul>
</>)}
const Search = ({ text, value, onChange }) => {
return (
<>
{text}
<input value={value} onChange={onChange} />
</>)}
const CountryMany = ({ country, handleClick }) => {
return (
<>
<li>{country.name}</li>
< Button onClick={handleClick(country.name)} text='Show' />
</>)}
const CountryFound = ({ countryFound, api_key, handleWeather, newWeather }) => {
const params = { access_key: api_key, query: countryFound.capital }
useEffect(() => {
axios.get('http://api.weatherstack.com/current', {params})
.then(response => {
console.log('RESPONSE', response.data)
handleWeather(response.data)
})})
const languages = countryFound.languages.map(lang => lang.name)
if (newWeather.length > 0 ){
return (
<>
< Header text={countryFound.name} />
<p>Capital: {countryFound.capital}</p>
<p>Population: {countryFound.population}</p>
< List title='Languages' stuff={languages} />
< Header3 text='Flag' />
< Image source={countryFound.flag} alttext='flag' />
< Header3 text='Weather' />
<ul>
<li>Temperature/rendering {newWeather}</li>
<li> Image source= alttext=weather </li>
</ul></>)}
return (
<></>
)}
const Countries = (props) => {
console.log('COUNTRIES PROPS', props)
console.log('WEATHER', props.newWeather)
const foundCountries = props.countries.filter(country =>
country.name.toLowerCase().includes(props.newSearch.toLowerCase()))
if (foundCountries.length > 10 ) {
return (<p>Too Many Matches, Keep Typing!</p>)}
if (foundCountries.length > 1) {
return (
<ul>
{foundCountries.map(country =>
< CountryMany key={country.population} country={country} handleClick={props.handleClick} />)}
</ul>)}
if (foundCountries.length === 1) {
return (
<>
<CountryFound api_key={props.a_k1} countryFound={foundCountries[0]}
handleWeather={props.handleWeather} newWeather={props.newWeather} />
</>)}
return (<></>)}
const App = () => {
const api_key = process.env.REACT_APP_API_KEY
const [ countries, setCountries ] = useState([])
const [ newSearch, setNewSearch ] = useState('af')
const [ newWeather, setWeather ] = useState([])
const handleClick = (value) => () => {
setNewSearch(value)}
const handleSearch = (event) => {
setNewSearch(event.target.value)}
useEffect(() => {
axios
.get('https://restcountries.eu/rest/v2/all')
.then(response => {
setCountries(response.data)
})}, [])
return (
<div>
< Search text='Find A Country: ' value={newSearch} onChange={handleSearch}/>
< Countries countries={countries}
a_k1={api_key}
handleWeather={setWeather}
handleClick={handleClick}
newSearch={newSearch}
newWeather={newWeather}
/>
</div>)}
export default App
最终编辑:已解决!
以下标记的解决方案解决了初始问题,但产生了无限循环。我已经整顿了整件事,尽管我还不太了解它是如何改变的。
import React, { useState, useEffect } from 'react'
import axios from 'axios'
const Header = ({ text }) => <h1>{text}</h1>
const Header3 = ({ text }) => <h3>{text}</h3>
const Image = ({ source, alttext }) => <img src={source} alt={alttext} />
const Button = ({ onClick, text }) => (<button onClick={onClick}>{text}</button>)
const ListItem = ({ item }) => <li>{item}</li>
const List = ({ title, stuff }) => {
return(
<>
< Header3 text={title} />
<ul>
{stuff.map((item, index) => < ListItem key={index} item={item} />)}
</ul>
</>)}
const Search = ({ text, value, onChange }) => {
return (
<>
{text}
<input value={value} onChange={onChange} />
</>)}
const CountryMany = ({ country, handleClick }) => {
return (
<>
<li>{country.name}</li>
< Button onClick={handleClick(country.name)} text='Show' />
</>)}
const CountryFound = ({ countryFound, api_key, handleWeather, newWeather }) => {
useEffect(() => {
axios.get(`https://api.weatherbit.io/v2.0/current?city=${countryFound.capital}&key=${api_key}`)
.then(response => {
handleWeather(response.data.data[0])
})})
const languages = countryFound.languages.map(lang => lang.name)
if (newWeather > '' ) {
const capital = countryFound.capital
const weatherTitle = `Weather in: ${capital}`
const weatherImage = `https://www.weatherbit.io/static/img/icons/${newWeather.weather.icon}.png`
return (
<>
< Header text={countryFound.name} />
<p>Capital: {capital}</p>
<p>Population: {countryFound.population}</p>
< List title='Languages' stuff={languages} />
< Header3 text='Flag' />
< Image source={countryFound.flag} alttext='flag' />
< Header3 text={weatherTitle} />
< Image source={weatherImage} alttext='weather' />
<ul>
<li>Temperature: {newWeather.temp} degrees Celsius</li>
<li>Wind: {newWeather.wind_spd} mph towards {newWeather.wind_cdir}</li>
</ul></>)}
return (<><p>Loading...</p></>)}
const Countries = (props) => {
const foundCountries = props.countries.filter(country =>
country.name.toLowerCase().includes(props.newSearch.toLowerCase()))
if (foundCountries.length > 10 ) {
return (<p>Too Many Matches, Keep Typing!</p>)}
if (foundCountries.length > 1) {
return (
<ul>
{foundCountries.map(country =>
< CountryMany key={country.population}
country={country}
handleClick={props.handleClick} />)}
</ul>)}
if (foundCountries.length === 1) {
return (<>
<CountryFound api_key={props.a_k1} countryFound={foundCountries[0]}
handleWeather={props.handleWeather} newWeather={props.newWeather} />
</>)}
return (<></>)}
const App = () => {
const api_key = process.env.REACT_APP_API_KEY
const [ countries, setCountries ] = useState([])
const [ newSearch, setNewSearch ] = useState('af')
const [ newWeather, setWeather ] = useState('')
const handleClick = (value) => () => {
setNewSearch(value)}
const handleSearch = (event) => {
setNewSearch(event.target.value)}
useEffect(() => {
axios
.get('https://restcountries.eu/rest/v2/all')
.then(response => {
setCountries(response.data)
})}, [])
return (
<div>
< Search text='Find A Country: ' value={newSearch} onChange={handleSearch}/>
< Countries countries={countries}
a_k1={api_key}
handleWeather={setWeather}
handleClick={handleClick}
newSearch={newSearch}
newWeather={newWeather}
/>
</div>)}
export default App
答案 0 :(得分:1)
handleWeather
定义为带有两个参数
const handleWeather = ( is, data ) => () => {
setWeather( is, data )
console.log('HEY HANDLEWEATHER', newWeather)
}
但是当您调用它时,您只能传递一个参数
handleWeather({ is: 'weather', data: response.data })
此外,反应状态更新是异步的,并且在渲染周期之间是批量处理的,因此尝试在入队后立即控制台日志状态只会记录当前状态。
您应该选择接受两个参数并创建您想要的状态对象,或者将要存储的已创建对象始终传递给它。以下将使用后者。
const handleWeather = (newWeather) => () => setWeather(newWeather);
注意:目前,handleWeather
只是代理newWeather
对象,因此较小的优化可能不是 代理,因为函数签名匹配,即const handleWeather = setWeather
,或者直接传递setWeather
作为回调。
<Countries
countries={countries}
a_k1={api_key}
handleWeather={setWeather} // <-- directly pass state update function
handleClick={handleClick}
newSearch={newSearch}
newWeather={newWeather}
/>
使用效果来记录更新的newWeather
,并使用newWeather
作为依赖项。
useEffect(() => {
console.log('HEY HANDLEWEATHER', newWeather)
}, [newWeather]);