I\'m not sure I\'m doing the right thing, I mutate variable outside of setState, it\'s fine right? or there\'s more elegant way to do it?
state = {
persons:
In javascript, object assignment works by referece and hence Even if you mutate the variable outside of setState, it will still refer to the same reference of state as long as you do not clone your object. However if you clone it, a new instance will be created and the original one will not be affected
addRow = () => {
const persons = [...this.state.persons] // Clone it one level deep using spread
persons.push({
name: '',
age: ''
})
this.setState({
persons
})
}
The above can be done using simply spread syntax
and functional setState
like
addRow = () => {
this.setState(prevState => ({
persons: [...prevState.persons, { name: '', age: ''}]
}))
}
Although in your example there seems no difference between the two actions, there is major flaw in the initial implementation that you provided. In order to see the difference between cloning and pushing and just assigning the reference and pushing, you can see the codesandbox demo.
Basically when you create a new component to which if you pass the state persons as props, and you mutate at its original reference, in the componentWillReceiveProps
method, you see that the currentProps
and the nextProps
are both the same and hence if you have any check in the child component to take action if the persons prop changed, that would fail. Hence its extremely important to not mutate the value at its own reference
Without push and spread syntax, you can still avoid the mutation issue by using concat which create a new copy of the original array
addRow = () => {
this.setState(prevState => ({
persons: prevState.persons.concat([{ name: '', age: ''}])
}))
}
In my opinion, more elegant way would be to use functional setState
:
const newPerson = { name: '', age: -1 };
this.setState(prevState => ({ persons: [...prevState.persons, newPerson] })