Reactjs-setState previous state is the first argument, props as the second argument Reactjs-setState previous state is the first argument, props as the second argument reactjs reactjs

Reactjs-setState previous state is the first argument, props as the second argument


They say you should do like that instead of the below example.

// Wrongthis.setState({  counter: this.state.counter + this.props.increment,});

They can't assure the state will have the correct value if you access like this because setState() will happen asynchronously, other updates could occur and change the value. If you are going to calculate the state based on the previous state, you have to make sure you have the last and most up to date value, so they made setState() accept a function that is called with prevState and props, so you can have the correct value to update your state, like the example below.

 // Correctthis.setState((prevState, props) => ({  counter: prevState.counter + props.increment}));


To add to Bruno's answer, the correct function above is called a pure function. React is big on something called immutability which means that every declared value should never be changed from its original declaration if possible. The variables in that function aren't your actual props and state until you pass them in, which means on the javascript function stack (the thread that queues up sync and async calls) the values and references to properties will be stored differently, creating uncertainty of what the value will be in the "wrong" case.


React may batch multiple setState() calls into a single update for performance.

Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state.

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

setState() enqueues changes to the component state and tells React that this component and its children need to be re-rendered with the updated state.

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.

Understanding with a example

This concept may be hard to understand and specially why it could cause issues, so I wrote an example that show an error happening:

/* Imagine props and states is the same as this.props and this.state */var state = { counter: 0 } ; var props = { } ;/* Our fake implementation of react setState */var setStatesToRun = []function setState(myFunction) { setStatesToRun.push(myFunction); }/* Our fake implementation of react batch update */function batchRunStateUpdates() {  propsLocal = props  stateLocal = state  f1 = setStatesToRun.pop()  newState = f1(stateLocal, propsLocal)  // Will run increment by 3  console.log(newState) // newState: { counter: 3 }  console.log(state) // state: { counter: 0 }  f2 = setStatesToRun.pop()  newState = f2(newState, propsLocal) // Will run increment by 2  console.log(newState) // newState: { counter: 2 }  console.log(state) // state: { counter: 0 }  // ... get the next setState function loop  console.log("Will update global state")  state = newState    console.log(state) // state: { counter: 2 } // WRONG!}console.log(setStatesToRun) // []// RightsetState((prevState, props) => { counter: prevState.counter + 3 });// WRONG, using state (this.state)setState((prevState, props) => { counter: state.counter + 2 });console.log(setStatesToRun) // [func, func]batchRunStateUpdates();

At the top we have some fake versions of React's methods. Those are overly simplified, but help explain what happens.

Then, we use setState the same way we do in React. One usage is right, the other is wrong.

Notice the final global state should be state: { counter: 5 }, but because of how we didn't respect React's recommendations we got state: { counter: 2 }

You can play with this code in https://jsfiddle.net/oniltonmaciel/g96op3sy/