Why do we need to pass a callback function to the setState function?
TL;DR
To allow the
setStatefunction to use the actualprevious valueof the state.
Longer version
What if we call the setState function simultaneously?
From the example below, at first glance, we might say the state will be abc after clicking the button.
Try to play with the code below
1function SetStateDemo() {2 const [state, setState] = React.useState('')3
4 const handleClick = () => {5 setState(state + 'a')6 setState(state + 'b')7 setState(state + 'c')8 }9
10 return <>11 <p>State: {state}</p>12 <button onClick={handleClick}>Click Me</button>13 </>14}If you predicted that the new state would not be abc, then kudos to you.
If not, then let's discuss what happened.
1...2const handleClick = () => {3 // value of state is ''4 setState(state + 'a') // '' + 'a' = 'a'5 // value of state is STILL ''6 setState(state + 'b') // '' + 'b' = 'b'7 // value of state is STILL ''8 setState(state + 'c') // '' + 'c' = 'c'9 // final of state is 'c'10}11...We indeed called setState 3 times, but that does not mean the value of the state variable will update after calling setState.
Solution: pass a function to setState
1// BEFORE2setState(state + 'a')3
4// AFTER5setState((previousState) => {6 return previousState + 'a'7})8// OR9setState(prev => prev + 'a')Passing a function to setState will allow us to get the previous state value from the function's first argument.
Now check the result of our updated code.
1function SetStateDemoWithCallback() {2 const [state, setState] = React.useState('')3
4 const handleClick = () => {5 setState(prev => prev + 'a')6 setState(prev => prev + 'b')7 setState(prev => prev + 'c')8 }9
10 return <>11 <p>State: {state}</p>12 <button onClick={handleClick}>Click Me</button>13 </>14}How did it work?
Each callback function would have a reference to the recent state change(if there is any) as shown in the commented code below.
1...2const handleClick = () => {3 // value of state is ''4 setState(prev => prev + 'a') // '' + 'a' = 'a'5 // value of prev is 'a'6 setState(prev + prev + 'b') // 'a' + 'b' = 'b'7 // value of prev is 'ab'8 setState(prev => prev + 'c') // 'ab' + 'c' = 'c'9 // final state is 'abc'10}11...Conclusion
Pass a callback function to setState if it might be called multiple times
and the new state needs to be calculated based on the previous state.
