当前位置: 首页 > 面试题库 >

反应-不使用setState更改状态:必须避免吗?

董谦
2023-03-14
问题内容

我的代码有效,但是我有一个最佳实践问题:状态中有一组对象,并且用户交互一次将更改一个对象的值。
据我所知,我不应该直接更改状态,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});

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

var data = this.state.data.slice(0):这将形成一个浅表克隆,push和shift不会更改状态,但是在我的克隆中,我仍然具有指向状态数组元素的指针。因此,如果我更改了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]);
}

然后,我更改index处的值,如果为false则将其设置为true,否则将其设置为false:

data[index].is_collected = !data[index].is_collected;

并更改状态:

this.setState({data: data});

考虑到我的数组比较大还是很大,我猜想这个迭代会降低我的APP的性能。如果我知道出于任何原因这是正确的方法,我将支付该费用。但是,在此函数(clickCollect)中,我总是将新值设置为state,我不是在等待错误的API响应,该响应会说停止进行更改。在所有情况下,新值都会进入状态。实际上,我setState只要求UI再次呈现。所以问题是:

  1. 在这种情况下,是否必须创建深度克隆?(for var i in ...
  2. 如果没有,.slice(0)如果我的数组包含对象,则进行浅表克隆()是否有意义?更改是在数组内部的对象上进行的,因此浅表克隆仍会更改我的状态,就像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;

问题答案:

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

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

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

this.state.data[index].is_collected = !this.state.data[index].is_collected;
this.setState({data: this.state.data});

您应避免更改状态的原因是,如果您引用this.state.datasetState多次调用,则可能会丢失数据:

    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`

如果您真的对此感到担心,请访问immutable.js



 类似资料:
  • 问题内容: 所以我有这个: newDealersDeckTotal只是一个数字数组,例如,但是没有给出正确的总数,但是呢?我什至设置了超时延迟,以查看是否可以解决问题。任何明显的还是我应该发布更多代码? 问题答案: 通常是异步的,这意味着在您处于状态时,它尚未更新。尝试将日志放入方法的回调中。状态更改完成后执行:

  • 问题内容: 保持不变,尽管我在函数中调度了一个动作: 输出为NO_AUTH(的初始值) 减速器: 知道为什么吗? 问题答案: 您当前正在直接在未映射到的componentDidMount内部调度: 这应该做的工作: 现在,这将获得authState:

  • 在这种情况下,我更改选择元素并调用数据更新方法。该方法从状态获取值。但是当数据更新时,状态还没有改变。当您再次调用数据更新时,状态已经更新了如何正确进行更新? 反应成分

  • 我猜这可能与从父级打开有关,但我有其他组件,它们内部的状态发生变化,所以我有点困惑,为什么这个组件不尊重它的新状态。 谢谢

  • 所以我有这个: 只是一个数组的数字例如然而没有给出正确的总数,但?我甚至放了一个超时延迟,看看这是否解决了问题。任何明显的还是我应该发布更多的代码?

  • 有一个案例我很困惑。 我有一个对象redux状态:{show:true,creative:{name:'a',tags:[t1,t2,t3]}。此对象已通过“react redux”的“connect”功能映射到道具。 当我改变属性“显示”或“creative.name”时,它确实会触发重新渲染。但是如果我将t0追加到"creative.tags",它就不会运行re-渲染。 我必须分配一个新变量来