setState already allows you to extend the current state.
I don't get it.
setState already allows you to extend the current state.
I don't get it.
Setting a state is assigning the entire state object in this case:
setState({ a: 1, b: 2, c: 3 })
The next time i want to update that state (not replace it completely), I do: setState({...state, a: 4 })
or
setState(prevState => ({...prevState, a: 4 })) `for the sake of brevity, the extendState just hides the boilerplate away:
extendState({ a: 4 })
It's just a matter of convenience to me too. I just call it `updateState` in my projects. setState({...state, a: 4 })
If all extendState is doing is concealing the underlying function call, it's saving very little boilerplate and adding the cognitive load and potential issues related to the wrapper. import { useState } from 'react'
function App() {
const [count, setCount] = useState({ a: 0 })
return (
<button type="button" onClick={() => setCount({ ...count, a: count.a + 1 })}>
{count.a}
</button>
)
}
Cognitive load adds over time and I think it's so much simpler to break down such loads into smaller pieces that are documented well and abstract away the complexities/syntactic nuances. In short I keep forgetting to spread the previous state and that led to bugs for me.Edit: Yes, you are right about the stale state and that was one of the primary reasons for me to not make it a pattern everywhere.
It MIGHT work, but it is still incorrect code - you must always use an update function if you are updating state, it's not optional.
Let's put it another way to be clear. This code is using stale state, don't use stale state:
<button type="button" onClick={() => setCount({ ...count, a: count.a + 1 })}>
The example you give above is incorrect code - it does not work the way you think - you need to update your understanding of React. React batches the useState calls and executes them later - so you must be very clear about the data you are using in the useState function - picking up the state value from the enclosing code gives you a state value that you cannot trust.The ONLY reliable to way actually get the previous state is to use a function as the argument to setState.
In he example above, you think you are getting the current value of count, but it might be stale - this is critical to understand in React and if you don't understand it then you'll be fighting weird bugs forever.
If you wish to use existing state, when you pass an update function to setState then React ensures that the previous state argument passed in is in fact the previous state.
i.e:
<button type="button" onClick={() => setCount({ ...count, a: count.a + 1 })}>
should be: <button type="button" onClick={() => setCount(prevCount => ({ ...prevCount, a: prevCount.a + 1 }))}>
I think that's the correct brackets but HN is not an IDE.The rule is simple: if you are updating state, ALWAYS pass an update function.
The reason I have an issue with the topic of this HN post is that updating state is critically important in React and you should understand how it works and do it correctly, with a function call that uses previous state. useState with a function call is not boilerplate to be abstracted away, it's a simple and unambiguous way of writing React code and is central to writing React apps correctly - don't hide this.
setState({ a: 4 })
https://reactjs.org/docs/react-component.html#setstateFrom React's "Using the State Hook" docs:
> However, unlike this.setState in a class, updating a state variable always replaces it instead of merging it.
https://reactjs.org/docs/hooks-state.html#tip-using-multiple...
The `extendState` method gives you the same convenience of `this.setState` but with hooks in function components instead of class components.
I was replying to the poster who was using:
setState({...state, a: 4})
and so I assumed they were already operating in a class component.