Answer the question
In order to leave comments, you need to log in
Why is the state not updated in the component?
Hello! While learning React, I am making an application to display the current weather and ran into a problem.
There is a class that makes a weather request and puts the necessary data from the response into the data object:
export default class AskForWeather {
getNeededData = async () => {
const city = "ulyanovsk"; //"479123";
const url = "http://api.openweathermap.org/data/2.5/weather?q=" + city + "&appid=b1b35bba8b434a28a0be2a3e1071ae5b&units=imperial";
let data = {};
await fetch(url).then((res) => res.json()).then(json => {
data = { temperature: json.main.temp }
})
return data;
}
}
import React, { Component } from 'react';
import Main from "../main/main.js"
import AskForWeather from "../../service/parser.js"
export default class App extends Component {
constructor(props) {
super(props);
this.state = { weather: null }
}
askForWeather = new AskForWeather();
openData = () => {
this.setState(() => {
return { weather: this.askForWeather.getNeededData() }
});
}
componentDidMount() {
this.openData();
}
render() {
return(
<div className= "container">
<Header />
<Main temperature={this.state.weather.temperature}/>
<Additional />
</div>
);
}
}
import React, { Component } from 'react';
const Main = (props) => {
const temperature = props.temperature;
return (
<section className="main">
<div className="temperature">
<span>{temperature} C</span>
</div>
<div className="weather-desc">
<img className="weather" src="" alt="#"></img>
<span className="desc">Тепло</span>
</div>
</section>
)
}
export default Main;
Answer the question
In order to leave comments, you need to log in
let data = {};
await fetch(url).then((res) => res.json()).then(json => {
data = { temperature: json.main.temp }
})
return data;
return fetch(url).then(r => r.json());
this.setState(() => {
return { weather: this.askForWeather.getNeededData() }
});
this.askForWeather.getNeededData().then(weather => {
this.setState(() => ({ weather }));
});
<Main temperature={this.state.weather.temperature}/>
{this.state.weather && <Main temperature={this.state.weather.main.temp} />}
In the Main prop, pass this.state.weather.temperature, that is, the field of the weather object, but it does not exist, since it is initially null, but the render method does not wait until the request is made and immediately tries to pass the prop when calling render.
Do a null check on the this.state.weather object or add a ready field to the state
Thanks for the replies, your tips worked!
I changed it, however, and as a result the code became like this:
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
weather: {},
isReadyToRender: false
}
}
askForWeather = new AskForWeather();
openData = () => {
this.askForWeather.getNeededData().then(weather => {
this.setState({
weather: weather,
isReadyToRender: true // стейт обновился, флаг стал true
});
})
}
componentDidMount() {
let timerId = setTimeout(() => {
this.openData();
}, 5000);
this.openData();
}
render() {
if (this.state.isReadyToRender) { //если стейт обновлен и флаг в нем изменен на true
return(
<div className= "container">
<Header />
<Main temperature={this.state.weather.main.temp} />
<Additional />
</div>
);
} else {
return null;
}
}
}
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question