0

i am trying to get data from an external API and use it to change the state on my app. The data actually shows up in the console but when i run set state does not change the state of my app.

class App extends Component {
  state={
    jobs:[]
  }


  onTermSubmit=(term)=>{
    const proxy=`https://cors-anywhere.herokuapp.com/`;
        const api = `${proxy}https://--------/positions.json?description=${term}&page=1`;

    fetch(api).then(res=>res.json()).then(data=>this.setState({jobs:data}))
    console.log(this.state)
  }

I am trying to get the state to change to the data returned from the API

Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
  • Possible duplicate of [Why calling react setState method doesn't mutate the state immediately?](https://stackoverflow.com/questions/30782948/why-calling-react-setstate-method-doesnt-mutate-the-state-immediately) – Emile Bergeron Oct 03 '19 at 16:26

2 Answers2

3

Both fetch() and setState() are asynchronous so attempting put a console.log() statement after the expression will not wait for the fetch or setState() to complete/resolve. Instead you can use the callback argument of setState() to console.log() only after fetch has resolved and setState() has updated state. From the documentation:

setState() does not always immediately update the component. It may batch or defer the update until later. This makes reading this.state right after calling setState() a potential pitfall. Instead, use componentDidUpdate or a setState callback (setState(updater, callback)), either of which are guaranteed to fire after the update has been applied. If you need to set the state based on the previous state, read about the updater argument below.

fetch(api)
  .then(res => res.json())
  .then(data =>
    this.setState({ jobs: data }, () => {
      console.log(this.state);
    })
  )
  .catch(err => console.log(err));

Hopefully that helps!

Alexander Staroselsky
  • 37,209
  • 15
  • 79
  • 91
0

As mentioned by @Alexander Staroselsky fetch() and setState() are asynchronous operations and the application won't wait until they are done to continue to the next operation thus resulting in this.state.jobs to still be an empty array.

My solution would be to make them synchronous by adding the async/await keyword before calling he function like this.

onTermSubmit= async (term)=> {
    const proxy=`https://cors-anywhere.herokuapp.com/`;
    const api = `${proxy}https://--------/positions.json?description=${term}&page=1`;

    let rawRes = await fetch(api)
    let jsonRes = await rawRes.json()
    await this.setState({jobs:rawRes}))
    console.log(this.state)
}

Just another approach

Hope this is helpful

Shmili Breuer
  • 3,927
  • 2
  • 17
  • 26