add row without push in es6 for react state

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: [{
      name: 'jay',
      age: 10
    }]
  }
  addRow = () => {
    const temp = this.state
    temp.persons.push({
      name: '',
      age: ''
    })
    this.setState({
      ...temp
    })
  }

App demo https://codesandbox.io/s/ppqw4wjqzq

Answers:

Answer

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: ''}])
    }))
  }
Answer

In my opinion, more elegant way would be to use functional setState:

const newPerson = { name: '', age: -1 };
this.setState(prevState => ({ persons: [...prevState.persons, newPerson] })

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us Javascript

©2020 All rights reserved.