I have below piece of code -
class Sum extends React.Component {
constructor(props) {
super(props)
this.state = { a : 0 }
}
// let's call this ADD-1
add = () => {
this.setState({ a: this.state.a + 1 })
this.setState({ a: this.state.a + 2 })
this.setState({ a: this.state.a + 3 })
}
render() {
return (<div>
<button onClick={this.add}> click me </button>
<div> sum {this.state.a} </div>
</div>)
}
}
this renders on clicking the button
sum = 3
where as i was hoping that it will render sum = 6
i.e 1 + 2 + 3
also, if I change my add
method to something like to accommodate for prevState
race condition-
// let's call this ADD-2
add = () => {
this.setState({ a: this.state.a + 1 })
this.setState({ a: this.state.a + 2 })
this.setState(prevState => ({ a: prevState.a + 1 }))
this.setState(prevState => ({ a: prevState.a + 4 }))
}
it renders sum = 7
whereas I was hoping for sum = 8
i.e (1 + 2 + 1 + 4)
Now two questions come to my mind:-
1) Why do we see the results as the one mentioned above and not what I have expected?
2) Why don't I see the transition of addition in UI?
Say if we consider method tagged as ADD-1
, I should be seeing something like sum = 1
then sum = 3
then sum = 6
. Is it because of batching of updates but batching puts them in a queue of execution it doesn't override anything in my opinion.
State update maybe asynchronous. Check this answer.
In an answer by Dan abramov, it is stated that state updates within one event call will only produce a single re-render at the end of the event.
no matter how many setState() calls in how many components you do inside a React event handler, they will produce only a single re-render at the end of the event.
And also batching happens only for state updates within a React event handler i.e batching does not happen inside AJAX calls
promise.then(() => {
// We're not in an event handler, so these are flushed separately.
this.setState({a: true}); // Re-renders with {a: true, b: false }
this.setState({b: true}); // Re-renders with {a: true, b: true }
this.props.setParentState(); // Re-renders the parent
});
But you could achieve what you want to by passing a callback to the setState
method
add = () => {
this.setState({ a: this.state.a + 1 },
() => {
this.setState({ a: this.state.a + 2 },
() => {
this.setState({ a: this.state.a + 3 })
})
})
}
The above will return sum = 6.
When not to use callbacks in setState :
PureComponent
andshouldComponentUpdate
can be used to tune up a component’s performance. They work by preventing lifecycle methods from firing when props and state haven’t changed.The
setState
callback fires regardless of whatshouldComponentUpdate
returns. So, thesetState
callback will fire, even when state hasn’t changed.