Reputation:
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});
}
Upvotes: 2
Views: 11365
Reputation: 6221
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
Upvotes: 5
Reputation: 130092
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} }));
}
Upvotes: 1
Reputation: 143
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.
Upvotes: 0
Reputation: 15292
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}});
}
Upvotes: 1
Reputation: 1170
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}})
Upvotes: 0