添加行而不推入 es6 以获得react状态

IT技术 javascript reactjs ecmascript-6
2021-05-25 02:26:04

我不确定我是否在做正确的事情,我在 setState 之外改变了变量,这没问题吧?或者有更优雅的方式来做到这一点?

state = {
    persons: [{
      name: 'jay',
      age: 10
    }]
  }
  addRow = () => {
    const temp = this.state
    temp.persons.push({
      name: '',
      age: ''
    })
    this.setState({
      ...temp
    })
  }

应用演示https://codesandbox.io/s/ppqw4wjqzq

2个回答

在 javascript 中,对象分配通过引用工作,因此即使您在 setState 之外改变变量,只要您不克隆对象,它仍然会引用相同的状态引用。但是,如果您克隆它,则会创建一个新实例,而不会影响原始实例

addRow = () => {
    const persons = [...this.state.persons] // Clone it one level deep using spread
    persons.push({
      name: '',
      age: ''
    })
    this.setState({
      persons
    })
  }

以上可以使用 simplespread syntaxfunctional setStatelike来完成

addRow = () => {
    this.setState(prevState => ({
      persons: [...prevState.persons, { name: '', age: ''}]
    }))
  }

尽管在您的示例中,这两个操作之间似乎没有区别,但您提供的初始实现存在重大缺陷。为了查看克隆和推送与仅分配引用和推送之间的区别,您可以看到codesandbox demo.

基本上,当您创建一个新组件时,如果您将状态人作为props传递给该组件,并在其原始引用处进行变异,则在componentWillReceiveProps方法中,您会看到 thecurrentProps和 thenextProps都是相同的,因此如果您对子项进行任何检查如果人员props发生变化,则采取行动的组件将失败。因此,不要在其自己的参考中改变值是非常重要的

没有 push 和 spread 语法,您仍然可以通过使用 concat 创建原始数组的新副本来避免变异问题

addRow = () => {
    this.setState(prevState => ({
      persons: prevState.persons.concat([{ name: '', age: ''}])
    }))
  }

在我看来,更优雅的方法是使用功能setState

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