在React组件的状态下存储对象?


76

是否可以在React组件的状态下存储对象?如果是,那么我们如何使用来更改该对象中键的值setState?我认为在语法上不允许这样写:

this.setState({ abc.xyz: 'new value' });

同样,我还有一个问题:在React组件中可以有一组变量,以便可以在组件的任何方法中使用它们,而不是将它们存储在状态中,这可以吗?

您可以创建一个包含所有这些变量的简单对象,并将其放置在组件级别,就像在组件上声明任何方法一样。

很可能会遇到这样的情况,即您在代码中包含了很多业务逻辑,并且需要使用许多变量,这些变量的值可以通过几种方法更改,然后您可以根据这些值更改组件的状态。

因此,您不必保留所有这些变量处于状态,而只需保留其值应直接反映在UI中的那些变量。

如果这种方法比我在这里写的第一个问题更好,那么我就不需要在状态中存储对象。

Answers:


38

除了kiran的帖子之外,还有更新助手(以前是react addon)。可以使用以下命令与npm一起安装npm install immutability-helper

import update from 'immutability-helper';

var abc = update(this.state.abc, {
   xyz: {$set: 'foo'}
});

this.setState({abc: abc});

这将创建一个具有更新值的新对象,并且其他属性保持不变。当您需要执行诸如推入数组并同时设置其他值之类的操作时,此功能将更为有用。有些人在各处使用它,因为它提供了不变性。

如果这样做,您可以采取以下措施来弥补

shouldComponentUpdate: function(nextProps, nextState){
   return this.state.abc !== nextState.abc; 
   // and compare any props that might cause an update
}

因此,我想将状态存储在之外的任何地方this.state,并render()在其中进行任何更改时都调用会容易得多。在经验丰富的React开发人员中,这完全被否定了吗?
安迪

render是一个纯函数,实际上不执行任何操作。有更新时,由react调用,而更新是由setState调用引起的。最佳做法是,您的渲染应针对相同的道具和状态产生相同的输出。这也使诸如shouldComponentUpdate之类的优化变得简单。
Brigand 2015年

哇,我离开SO这么久了吗?实际上,forceUpdate()每当Backbone模型的给定字段发生更改时,我实际上都使用了一些基本的反应性工具来调用。因此,我可以简单地重写shouldComponentUpdate以返回false。render仍然会针对相同的props“状态”产生相同的输出(即Backbone模型,我不会在中存储任何内容this.state)。
安迪

1
@Sebastialonsorequire('react-addons-update')并安装它。
Brigand

1
似乎该帮助程序现在已成为旧版,建议改为使用该库:github.com/kolodny/immutability-helper
asiop

88
  1. this.setState({ abc.xyz: 'new value' });语法不允许。您必须传递整个对象。

    this.setState({abc: {xyz: 'new value'}});
    

    如果您在abc中还有其他变量

    var abc = this.state.abc;
    abc.xyz = 'new value';
    this.setState({abc: abc});
    
  2. 如果它们不依赖this.props和,则可以具有普通变量this.state


13
如果要在对象中保留其他属性,则使用下划线的extend这样的方法很有用:this.setState({abc: _.extend(this.state.abc, {xyz: 'new value'})});
smhg 2014年

1
@smhg不太update强大,因为它支持用于修改状态内部复杂对象的命令,因此功能更强大。当您不需要这些特殊功能时,我认为_.extend它提供了一种更简洁的语法,尤其是对于后来阅读代码并且不熟悉的目的的人update
佐尔坦

2
@smhg,要补充一点,Object.assign如果您的浏览器支持ES6(或仅使用polyfill),则可以使用
Jay

1
@kiran将复杂对象设置为变量不会复制它,它只是对同一对象进行了另一个引用。因此, var abc = this.state.abc; abc.xyz = 'new value';this.state.abc.xyz='new value'
jasonseminara '16

1
这个答案看起来很可疑,就像OP直接在修改状态一样,这是一个很大的禁忌。假设abc只有原始字段,则正确的第一行应为var abc = { ...this.state.abc };
Chris G


15

this.setState({abc: {xyz: 'new value'}});将不起作用,因为state.abc将被完全覆盖,不合并。

这对我有用:

this.setState((previousState) => {
  previousState.abc.xyz = 'blurg';
  return previousState;
});

除非我读错文档,否则Facebook建议使用上述格式。 https://facebook.github.io/react/docs/component-api.html

另外,我猜想不更改状态的最直接方法是使用ES6传播/休息操作员直接复制:

const newState = { ...this.state.abc }; // deconstruct state.abc into a new object-- effectively making a copy
newState.xyz = 'blurg';
this.setState(newState);

我使用来测试了您的第一种方式componentDidUpdate(),它正确地保持了先前的状态,同时this.setState({[abc.xyz]: 'blurg'})给出了错误的先前状态,因此我认为它很好。
马丁·道森

前一个状态实际上不是上一个状态。这是currentState,这是不正确的。
Martin Dawson


previousState.abc.xyz = 'blurg';改变当前状态,这是React中的反模式。
Emile Bergeron

8

即使可以通过不可变性帮助程序或类似方法完成此操作,除非确实需要,否则我不会在代码中添加外部依赖项。当我需要做时,我使用Object.assign。码:

this.setState({ abc : Object.assign({}, this.state.abc , {xyz: 'new value'})})

也可以在HTML事件属性上使用,例如:

onChange={e => this.setState({ abc : Object.assign({}, this.state.abc, {xyz : 'new value'})})}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.