3 ms·
Based on your other replies I think you got it already, but I'll just add it here for the sake of others. Setting a state is assigning the entire state object
by mlnj 5y ago
Based on your other replies I think you got it already, but I'll just add it here for the sake of others.
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.
- andrewstuart 5y agoAs mentioned elsewhere, this is invalid code - a bug waiting to show itself - you should never do: 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.
- drdec 5y agoThe docs for setState say that if passed an object it will merge the current state and the object. So just do: setState({ a: 4 }) https://reactjs.org/docs/react-component.html#setstate https://reactjs.org/docs/react-component.html#setstate
- loh 5y agoThe docs you linked to are for class components (`this.setState`), not function components using hooks (`useState`). From 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-state-variables 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.
- drdec 5y agoThanks for the clarification. 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.
- mlnj 5y agoNot sure what you mean by invalid code. This is working code. 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.
- andrewstuart 5y ago>> Not sure what you mean by invalid code. This is working code. 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.