React - 在不使用setState的情况下更改状态:必须避免它吗?

Sza*_*aci 9 javascript arrays state setstate reactjs

我的代码有效,但我有一个最佳实践问题:我在状态中有一个对象数组,用户交互将一次更改一个对象的值.据我所知,我不应该直接改变状态,我应该总是使用setState.如果我想以任何代价避免这种情况,我将通过迭代深度克隆数组,并更改克隆.然后将状态设置为克隆.在我看来,避免改变我以后会改变的状态只会降低我的表现.

详细版本: this.state.data是一个对象数组.它代表论坛中的主题列表,收藏夹按钮将切换,调用clickCollect().由于我在状态中有一个数组,当我更改一个项的is_collected属性时,我需要创建一个要使用的数组的副本,并在更改为新值后,我可以将其设置为状态.

var data = this.state.data.slice(0);
data[index].is_collected = !data[index].is_collected;
this.setState({data: data});
Run Code Online (Sandbox Code Playgroud)

var data = this.state.data:这会将指针复制到数组,push(),shift()等会直接改变状态.双方datathis.state.data会受到影响.

var data = this.state.data.slice(0):这使得浅层克隆,推送和移位不会改变状态,但在我的克隆中,我仍然有指向状态数组元素的指针.所以,如果我改变data[0].is_collected,this.state.data[0].is_collected也会改变.这发生在我打电话之前setState().

通常我应该这样做:

var data = []; 
for (var i in this.state.data) {
    data.push(this.state.data[i]); 
}
Run Code Online (Sandbox Code Playgroud)

然后我更改index的值,当它为false时将其设置为true,否则为true时:

data[index].is_collected = !data[index].is_collected;
Run Code Online (Sandbox Code Playgroud)

并改变状态:

this.setState({data: data});
Run Code Online (Sandbox Code Playgroud)

考虑我的阵列相对较大或非常大,我想这次迭代会降低我的APP的性能.如果我知道这是出于任何原因的正确方法,我会支付这笔费用.但是,在这个函数(clickCollect)中,我总是将新值设置为状态,我不是在等待一个错误的API响应,它会说停止进行更改.在所有情况下,新值都将进入状态.实际上我setState只调用UI再次渲染.所以问题是:

  1. 在这种情况下,我是否必须创建深度克隆?(for var i in ...)
  2. 如果没有,.slice(0)如果我的数组包含对象,那么生成浅层clone()是否有意义?正在对数组内部的对象进行更改,因此浅层克隆仍会更改我的状态,就像copy(data = this.state.data)一样.

为简单起见,我的代码被简化并且API调用被删除.

这是一个初学者的问题,所以也欢迎采用完全不同的方法.或链接到其他问答.

import React from 'react';

var ForumList = React.createClass({
  render: function() {
      return <div className="section-inner">
        {this.state.data.map(this.eachBox)}
      </div>
  },
  eachBox: function(box, i) {
    return <div key={i} className="box-door">
        <div className={"favorite " + (box.is_collected ? "on" : "off")} onTouchStart={this.clickCollect.bind(null, i)}>
          {box.id}
        </div>
    </div>
  },
  getInitialState: function() {
    return {data: [
      {
        id: 47,
        is_collected: false
      },
      {
        id: 23,
        is_collected: false
      },
      {
        id: 5,
        is_collected: true
      }
    ]};
  },
  clickCollect: function(index) {
    var data = this.state.data.slice(0);
    data[index].is_collected = !data[index].is_collected;
    this.setState({data: data});
  }
});

module.exports = ForumList;
Run Code Online (Sandbox Code Playgroud)

Cod*_*Cat 5

就我个人而言,我并不总是遵守规则,如果您真正了解自己想要做什么,那么我认为这不是问题。

var data = this.state.data.slice(0);
data[index].is_collected = !data[index].is_collected;
this.setState({data: data});
Run Code Online (Sandbox Code Playgroud)

setState在这种情况下,像这样改变状态并再次调用就可以了

this.state.data[index].is_collected = !this.state.data[index].is_collected;
this.setState({data: this.state.data});
Run Code Online (Sandbox Code Playgroud)

您应该避免改变状态的原因是,如果您引用this.state.data, 并setState多次调用,您可能会丢失数据:

const myData = this.state.data
myData[0] = 'foo'
this.setState({ data: myData })
// do something...
// ...
const someNewData = someFunc()
this.setState({ data: someNewData })

myData[1] = 'bar' // myData is still referencing to the old state
this.setState({ data: myData }) // you lose everything of `someNewData`
Run Code Online (Sandbox Code Playgroud)

如果你真的关心这个,就去immutable.js