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

Posted

技术标签:

【中文标题】将对象存储在 React 组件的状态中?【英文标题】:Storing an object in state of a React component? 【发布时间】:2015-01-22 04:33:39 【问题描述】:

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

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

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

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

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

因此,不是将所有这些变量保留在状态中,而是只保留那些值应该直接反映在 UI 中的变量。

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

【问题讨论】:

【参考方案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);
    

    你可以有普通变量,如果它们不依赖 this.props 和 this.state

【讨论】:

如果你想在对象中保留其他属性,像下划线的extend这样的方法很有用:this.setState(abc: _.extend(this.state.abc, xyz: 'new value')); @smhg 不完全是,update 更强大,因为它支持 commands 用于修改状态内的复杂对象。当你不需要这些特殊功能时,我认为_.extend 提供了更简洁的语法,特别是对于稍后阅读代码并且不熟悉update 用途的人。 @smhg,添加到你的,如果你的浏览器支持 ES6(或者只使用 polyfill),你可以使用Object.assign @kiran 将复杂对象设置为变量不会复制它,它只是对同一对象进行另一个引用。所以,var abc = this.state.abc; abc.xyz = 'new value';this.state.abc.xyz='new value' 相同 这个答案看起来很可疑,就像 OP 正在直接修改状态,这是一个很大的禁忌。假设abc只有原始字段,正确的第一行应该是var abc = ...this.state.abc ;【参考方案2】:

您可以在对象中以前的值上使用ES6 spread 以避免覆盖

this.setState(
     abc: 
            ...this.state.abc,
            xyz: 'new value'
           
);

【讨论】:

【参考方案3】:

除了 kiran 的帖子,还有 update helper(以前的 a react addon)。这可以使用 npm install immutability-helper 与 npm 一起安装

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 这样的优化变得简单。 哇,我离开 SO 这么久了吗?实际上,每当主干模型的给定字段发生更改时,我实际上最终使用了一些基本的反应式工具来调用forceUpdate()。因此,我可以简单地覆盖 shouldComponentUpdate 以返回 false。 render 仍然为相同的 props 和“状态”产生相同的输出(即骨干模型,我没有在 this.state 中存储任何内容)。 @Sebastialonso require('react-addons-update') 当然安装它。 似乎这个助手现在是遗留的,建议使用这个库:github.com/kolodny/immutability-helper【参考方案4】:

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') 给出了不正确的之前的状态,所以我认为它很好。 previousState 实际上并不是previousState。是 currentState,这是不正确的。 ...this.state.abc will only copy over "methods" defined via object literals (since these are enumerable) but not methods defied via the "class" mechanism (since these aren't enumerable). previousState.abc.xyz = 'blurg'; 改变当前状态,这是 React 中的反模式。【参考方案5】:

在一行代码中更简单的方法

this.setState( object:  ...this.state.object, objectVarToChange: newData  )

【讨论】:

【参考方案6】:

即使它可以通过immutability-helper 或类似方式完成,我也不希望在我的代码中添加外部依赖项,除非我真的必须这样做。当我需要这样做时,我使用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'))

【讨论】:

【参考方案7】:

如果您想使用功能组件将对象存储在状态中,您可以尝试以下操作。

import React from 'react';
import useState, useEffect from 'react';

const ObjectState= () => 
    const [username, setUsername] =  useState();

    const usernameSet = () => 
        const name = 
            firstname: 'Naruto',
            familyname: 'Uzmaki' 
        
        setUsername(prevState => name);
    

    return(
        <React.Fragment>
            <button onClick= usernameSet>
                Store Object
            </button>
           username.firstname username.familyname 
        </React.Fragment>
    )


export default ObjectState;

如果要将对象添加到预先存在的对象。

import React from 'react';
import useState, useEffect from 'react';

const ObjectState= () => 
    const [username, setUsername] =  useState(village: 'Konoha');

    const usernameSet = () => 
        setUsername((prevState) => 
            const data = 
                ...prevState, 
                firstname: 'Naruto',
                familyname: 'Uzmaki' 
            
            return data
        );
    

    return(
        <React.Fragment>
            <button onClick= usernameSet>
                Store Object
            </button>
            username.village username.firstname username.familyname 
        </React.Fragment>
    )


export default ObjectState;

附言:将组件命名为“对象”会导致“最大调用堆栈大小” 超出错误'。其他名称很好,但由于某种原因,“对象”是 不是。 像下面这样不行。

    const Object = () => 
        // The above code
    ;

    export default Object;

如果有人知道为什么或如何阻止它,请将其添加到 cmets。

【讨论】:

最初的问题已经超过 6 年了,并且只涉及基于类的组件状态(这是唯一的状态机制)。基于类的状态和基于钩子的状态表现完全不同。但在你的回答中没有一个字。而且使用 useEffect 来初始化 state 实在是太麻烦了。 @Martin 感谢您的评论。我正在研究必须通过使用'useEffect'来初始化状态的东西,所以我没有想到它可能如此繁琐,所以感谢您指出这一点。我已将答案更改为可能不那么麻烦的东西。

以上是关于将对象存储在 React 组件的状态中?的主要内容,如果未能解决你的问题,请参考以下文章

如何从存储中更新 React Native 功能组件状态

从 React 状态对象中提取地理位置

如何访问组件外部的 react-redux 存储

无法从不同的文件定义导入的对象,将其存储在一个状态中并将其传播到 React 中的另一个变量中

REACT 如何在 setState 中存储对象而不是对象数组?

将 Flux 存储中的 Immutable.js 映射与内部 React 组件状态合并