2

I am trying to run the code above but the state get updated only for idx. From what i understand the second function's setState will not get the updated state and thats why this happens. Is there a way to make it work properly (expect than merge the 2 functions in one)

doIt(idx,array) {
   this.doFirst(array);
   this.doSecond(idx);
}

doFirst(array){
   //bla bla bla code
   this.setState(test: {...this.state.test, array});
}

doSecond(idx) {
    // bla bla bla code
    this.setState(test: {...this.state.test, idx});
}
RIYAJ KHAN
  • 15,032
  • 5
  • 31
  • 53

5 Answers5

5

setState() is asynchronous.

Think of setState() as a request rather than an immediate command to update the component. For better perceived performance, React may delay it, and then update several components in a single pass. React does not guarantee that the state changes are applied immediately.

it takes an optional callback function that will be executed once setState is completed and the component is re-rendered. you can use that callback.

If the next state depends on the previous state, it is recommended to use the updater function form setState(updater[, callback])

doIt(idx,array) {
   this.doFirst(array, () => this.doSecond(idx));
}

doFirst(array, callback){
   //bla bla bla code
   this.setState(firstUpdaterFunction, callback);
}

doSecond(idx) {
    // bla bla bla code
    this.setState(2ndUpdaterFunction);
}

References:

https://reactjs.org/docs/react-component.html#setstate

https://stackoverflow.com/a/41446620/2073920

Abdul Rauf
  • 5,798
  • 5
  • 50
  • 70
1

Below two statement executed simultaneously.

this.doFirst(array);
this.doSecond(idx);

These both calling setState.setState is asynchronous. So, there is no guarantee that value will be updates sequentially. Beacause of this race call,the value is getting overwritten. better to chain these call.

doIt(idx,array) {
   this.doFirst(array);   
}

doFirst(array){
   //bla bla bla code
   this.setState({test: {...this.state.test, array}},()=>{

    this.doSecond(idx); 
   });
}

doSecond(idx) { 
    this.setState({test: {...this.state.test, idx}});
}
RIYAJ KHAN
  • 15,032
  • 5
  • 31
  • 53
0

Hard to tell exactly because your example setState calls aren't quite right, this.setState(test: {...this.state.test, idx});. Do you mean you're doing this.setState({test: {...this.state.test, idx}});? If so you should use a callback instead of an object like this:

this.setState(() => ({ test: {...this.state.test, idx}})

Aaron Bruce
  • 1,130
  • 1
  • 12
  • 24
0

I'm assuming that you just misplaced your brackets around your state object, so I added those.

At any rate, you want to use the updater function instead:

this.setState((prevState, props) => ({test: {...prevState.test, array}});

Note that this is probably not what you want as in ES 2015 it translates to: this.setState((prevState, props) => ({test: {...prevState.test, array: array}});

You'd want to do the same thing for the other function as well. React batches set state calls together, so if you don't use the updater, there is a chance that you will be accessing a stale state for your successive function calls. That's probably what is happening in this case.

sledsworth
  • 143
  • 1
  • 8
0

As others have already pointed out, setState is asynchronous. If you need to use previous state I would like to point out that the first argument of setState is updater, it can take a function to calculate next state from the previous state:

doFirst(array){
   this.setState(previousState => ({ test: {...previousState.test, array} }));
}

doSecond(idx) {
    this.setState(previousState => ({ test: {...previousState.test, idx} }));
}
Sulthan
  • 128,090
  • 22
  • 218
  • 270