2

I'm having an issue with React state. It receives an array of objects and it's being set properly in state, but then function finishes it shows that state is empty. Can anyone explain this behaviour?

  componentDidMount() {
    this.getWeather();
    this.getForecast();
    this.setState({location: ''});
  }

  getWeather() {
    if (this.state.location === "") {
      this.setState({error: 'Please enter something'});
    } else {
      OpenWeather.getWeather(this.state.location).then(result => {
        if (result.cod === "404") {
          this.setState({error: 'City not found'});
        } else if (result.cod === 200) {
          this.setState({error: ''});
          this.setState({weather: result});
        } else {
          this.setState({error: 'Server error'});
        }
      });
    }
  }

  getForecast() {
    OpenWeather.getForecast(this.state.location).then(forecast => {
      console.log("Returned forecast:");
      console.log(forecast);
      this.setState({forecast: forecast});
      console.log("Forecast saved to state(inside function)");
      console.log(this.state.forecast);
    });
    console.log("Forecast saved to state(outside function)");
    console.log(this.state.forecast);
  }

Console output:

Forecast saved to state(outside function)
[]
Returned forecast:
(5) [{…}, {…}, {…}, {…}, {…}]
Forecast saved to state(inside function)
(5) [{…}, {…}, {…}, {…}, {…}]
Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
bordax
  • 77
  • 8

1 Answers1

3

There are two things, conceptually wrong.

First: Your API requests to OpenWeather. getForecast is asynchronous and hence before your API returns a response the Javascript code after it is being executed and hence you get the first response as

Forecast saved to state(outside function)
[]

Now when the Api results in Success, you get

Returned forecast:
(5) [{…}, {…}, {…}, {…}, {…}]

Second: Since setState is asynchronous, your third statement

console.log("Forecast saved to state(inside function)");
console.log(this.state.forecast);

may or may not give you the updated value. You should instead make use of setState callback.

Check these question for more info

When to use React setState callback

calling setState doesn't mutate state immediately

Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
  • ok. added async await to nearly all my Component methods. now it shows state being set after both functions finished running, but I still can't access state values in my render method. – bordax Dec 29 '17 at 15:34
  • Are you getting any error, how are you trying to access state – Shubham Khatri Dec 30 '17 at 04:07
  • as far as it is saved as list i try to access it by this.state.forecast[0].main, i try to hard code the state, that way i get normal response. added console.log to end of conponentWillMount and it did printed correct resuslts – bordax Dec 30 '17 at 10:27
  • 1
    @bordax, the reason it is not working is because initially `this.state.forecast[0]` isn't available, and hence accessing `main` from it will give you an error, you need to first initialise and empty array in state, and then add a check for the existence of `this.state.forecast[0]` before actually accessing it value – Shubham Khatri Dec 30 '17 at 10:30
  • well, it looks like I figured it out. I accidentally left hard coded values in the list and then uncommented getForecast() and it worked. it basicallly works if i set forecast state to [{}]. and found one more syntax mistake in my code this.state was missing semicolon at the end, don't know if it was related – bordax Dec 30 '17 at 10:56