Reputation: 603
I was watching a tutorial and in one moment he does this:
export default function Editor(props) {
const [open, setOpen] = useState(true);
return (
<div className={`container ${open ? "" : "collapsed"}`}>
<button onClick={() => setOpen((prevOpen) => !prevOpen)}>O/C</button>
</div>
);
}
My question is: why this
<button onClick={() => setOpen((prevOpen) => !prevOpen)}>O/C</button>
and not
<button onClick={() => setOpen(!open)}>O/C</button>
I tried both and they seem to work.
Upvotes: 3
Views: 7817
Reputation: 84902
Because open
may not actually be the previous state. In your code it is, but in more complicated components there may be multiple pieces of code that set state. If these happen at around the same time, react may batch them up and apply them all at once.
Usually, these pieces of code will be in separate parts of the component and thus it's hard to spot. But for demonstration purposes, i'll put them right next to eachother:
onClick={() => {
setOpen(!open)
setOpen(!open)
})
With the above code, we ask react to set the state to false
, and then we ask react to set the state to false
again. End result is that it's false. That's probably not what's intended: if we toggle the state twice, it's probably because we want it to go back to the original state.
onClick={() => {
setOpen((prevOpen) => !prevOpen)
setOpen((prevOpen) => !prevOpen)
})
This code will set it to false
, and then set it to true
. Each function gets passed in the most recent value, even if that value is different than the value of open
in the closure.
Upvotes: 8
Reputation:
When you want to update the state which depends on the previous state then you need to call the setState like <button onClick={() => setOpen((prevOpen) => !prevOpen)}>O/C</button>
. This is the important rule of how you set the state.
Upvotes: 0