In React, the state is immutable. In simple terms it means that you should not modify it directly. Instead a new object should be created to set the state using setState
.
Here are two examples.
Modifying the state directly - Not Acceptable
onChange(event) {
this.state.value = event.target.value
}
Using setState()
- Acceptable
onChange(event) {
this.setState({ value: event.target.value })
}
The above is clear to almost all react developers. However, developers still make the above mistake accidentally. Have a look at the code snippet below.
Common Mistake
const [arr, setArr] = useState([])
const handleSubmit = (event) => {
event.preventDefault()
arr.push("New Item")
setArr(arr)
}
In the above code snippet the developer did use setArr
but still modified the arr
. The .push()
modifies the arr
.
Why will the above code not work?
React compares the previous state with the updated state to decide if the component needs to be re-rendered. Modifying the state directly will disturb this process. As a result the component will behave unexpectedly. In some cases not re-rendering at all even though the state has been modified.
The above mistake is independent of functional or class components.
Solution
const [arr, setArr] = useState([])
const handleSubmit = (event) => {
event.preventDefault()
setArr([...arr, "new value"])
}
The spread syntax creates a copy of the array. Hence we are not modifying the original array.
Subtler Way of Making the Same Mistake
const [obj, setObj] = useState({
key: 'value',
})
const handleSubmit = (event) => {
event.preventDefault()
const tempObj = obj
tempObj.key = "new value"
setObj(tempObj)
}
In the above snippet, it may seem at first that we made a copy of obj
and modified that but in JavaScript the objects copied through reference. In other words, tempObj
and obj
are the same. Any changes made to tempObj
is also reflected on obj
.
CodeSandbox Demo
Top comments (0)