Bug: useState Hook has different behaviour than class state when it is an object
CapsLockTeam opened this issue · comments
React version: 17.0.2
The current behavior:
Very buggy. Sometimes it rerenders the checkbox and is displayed correctly, other times it just stays with original value.
The expected behavior:
That the object in the state updates correctly to true/false based on the checkbox state. It works like that in class components.
Steps To Reproduce:
- Set an object with some key as a state object (through UseState hook).
- Use input checkbox and set it as checked variable. For example: <input type="checkbox" checked={someObject.key} onChange={() => setSomeObject(function(oldObject){oldObject.key = !oldObject.key; return oldObject})}/>
Code example:
https://codesandbox.io/s/peaceful-galois-89rfk?file=/src/App.js
Just based on that snippet, you are mutating oldObject
, and then returning it. That will always break. useState
and useReducer
require immutable updates - you always have to make a copy of the original data, modify it, and return that copy:
- https://reactjs.org/docs/hooks-reference.html#bailing-out-of-a-state-update
- https://daveceddia.com/react-redux-immutability-guide/
- https://blog.isquaredsoftware.com/2020/05/blogged-answers-a-mostly-complete-guide-to-react-rendering-behavior/#immutability-and-rerendering
Class component this.setState()
actually lets you "mutate" the state and it still re-renders. You shouldn't do that - React has always emphasized immutability - but it "works".
Of course, in my code I use the spread syntax to return a new object.
Reason why I opened this is, is because it works with class components.
Also, it works in useState hook with all other inputs I've tested like text, password, select and so on where the state object is an object reference which contains a key that points to a value of a reference to a string.
That is exactly my point. There is a known intentional difference in behavior between useState/useReducer
and class component this.setState
. The hooks require immutable updates. this.setState
does not. This is not a bug, it's an intentional evolution in React's design.
You cannot mutate existing state values with the hooks and expect the UI to update correctly or consistently.
Oh, I was not aware of this, only started recently using React for a project and all I know is through the docs.
Thank you for the clarification @markerikson !