当前位置: 首页 > 知识库问答 >
问题:

如何在React中更新嵌套状态,状态应该是不可变的吗?

邹杰
2023-03-14

我们正在热烈讨论如何在React中更新嵌套状态。国家是否应该是不可改变的?优雅地更新状态的最佳实践是什么?

假设你有这样的状态结构:

this.state = { 
                numberOfStudents: "3",
                gradeLevel: "5",
                students : [ 
                    { id : "1234",
                      firstName: "John",
                      lastName: "Doe",
                      email: "johndoe@mail.com"
                      phoneNumer: "12345"

                    },
                    { id : "56789",
                      firstName: "Jane",
                      lastName: "Doe",
                      email: "janedoe@mail.com"
                      phoneNumer: "56789"
                    },
                    { id : "11111",
                      firstName: "Joe",
                      lastName: "Doe",
                      email: "joedoe@mail.com"
                      phoneNumer: "11111"
                    }
                ]
            }

然后我们要更新乔·多伊的电话号码。我们有几种方法可以做到这一点:

将状态强制更新更改为重新加载

this.state.students[2].phoneNumber = "9999999";
this.forceUpdate();

带变异状态的变异状态集合状态

this.state.students[2].phoneNumber = "9999999";
this.setState({
     students: this.state.students
});

Object.assign,这仍然会改变状态,因为new学生只是对this.state指向的同一对象的新引用

const newStudents = Object.assign({}, this.state.students);
newStudents[2].phoneNumber = "9999999"
this.setState({
     students: newStudents
});

更新不变性助手(https://facebook.github.io/react/docs/update.html)设定状态。如果我们在每个学生对象中都有address.street、address.city、address.zip,并且想要更新街道,这可能会很快变得丑陋。

const newStudents = React.addons.update(this.state.students, {2: {phoneNumber: {$set:"9999999"}}});
this.setState({
     students: newStudents
})

setState的react文档的最后一行说明:

切勿直接对this.state进行变异,因为之后调用setState()可能会替换您所做的变异。将this.state视为不可变的。https://facebook.github.io/react/docs/react-component.html

文件规定,我们不应使用forceUpdate重新提交:

通常,您应该尽量避免使用forceUpdate(),而只从render()中的this.props和this.state读取。

为什么会是这种情况,如果我们改变状态并在之后调用setState会发生什么?在什么情况下setState()将取代我们所做的突变?这是一个非常令人困惑的说法。有人能解释一下我们在上面设置状态时使用的每种场景的可能复杂性吗。

共有1个答案

贾沛
2023-03-14

html" target="_blank">声明:

"bject.assign,这仍然会使状态发生变化,因为新学生只是对相同对象的新引用this.state指向"

此语句不正确。
Object.assign会将传入的状态变异为其第一个参数。由于您传入了一个空的对象文本({}),因此您正在变异新的对象文本,而不是此.state

不变状态原理与函数式编程有联系。

它在React中很有用,因为它为React提供了一种知道状态是否已经改变的方法,一个有用的用例是优化组件何时应该重新渲染

考虑具有嵌套对象的复杂状态的情况。改变状态的值会改变状态中属性的值,但不会改变对象的引用。

this.state = {nestObject:{nestedObj:{nestObj:'yes'}}};

// mutate state
this.state.nestObject.nestedObj.nestObj= 'no';

我们如何知道React是否应该重新渲染组件?

  1. 深度平等检查?想象一下,在一个复杂的状态下,每次状态更新都会有数百甚至数千次检查……
  2. 无需检查更改,只需在每次状态更改时强制重新渲染所有内容即可

后两种方法是否有替代办法?

通过创建一个新对象(从而创建一个新引用),使用object.assign复制旧状态并对其进行变异,您可以操纵状态值并更改对象引用。

使用不可变状态方法,我们可以通过简单地检查对象引用是否相等来知道状态是否已经改变。

考虑这个简单的例子:

this this.state = { someValue: 'test'}
var newState = Object.assign({}, this.state);
console.log(newState);                  // logs: Object {someValue: "test"]  
console.log(this.state);                // logs: Object {someValue: "test"]

// logs suggest the object are equal (in property and property value at least...

console.log(this.state === this.state); // logs: true

console.log(this.state === newState);   // logs: false.  Objects are 
                                        // pass-by-reference, the values stored
                                        // stored in this.state AND newState
                                        // are references.  The strict equality
                                        // shows that these references
                                        // DON'T MATCH so we can see
                                        // that an intent to modify
                                        // state has been made
 类似资料:
  • 问题内容: 我试图通过使用这样的嵌套属性来组织我的状态: 但是像这样更新状态 不起作用。如何正确完成? 问题答案: 为了创建嵌套对象,您可以按照以下方法进行操作,因为我认为setState无法处理嵌套更新。 这个想法是创建一个虚拟对象,对其执行操作,然后用更新的对象替换组件的状态 现在,散布运算符仅创建对象的一级嵌套副本。如果您的状态是高度嵌套的,例如: 您可以在每个级别使用传播运算符来设置状态,

  • 我正在尝试学习React(使用redux),所以我正在制作一个应用程序,在其中我可以创建训练计划,将训练添加到计划中,然后将训练添加到训练中。 PlanListComponent 我的PlansList组件为每个计划呈现一张卡片。在这张卡片中,它为该计划中的每个训练呈现一个训练列表。将训练添加到计划后,“计划列表”组件不会重新渲染。添加的训练仅在我刷新页面后显示。我之所以选择这种情况,是因为我必须

  • 谁能告诉我我在这里做错了什么?从console.log,我可以看到日期功能正在正常工作。但是,即使在之后,时间戳也不会更新。提前感谢!

  • 更新树结构中的嵌套组件时遇到问题。我创建了以下示例来说明这个问题:Codesandbox.io 为完整起见,这是正在嵌套的组件: 树中的节点在单击时应该是可选择的,我还希望在所有子节点中(递归地)切换所选状态。我想我可以通过将通过道具传递给孩子们来实现这一点,不幸的是,这似乎不起作用。 但是,子对象使用其旧状态重新呈现(可以理解,因为它们没有通过构造函数重新初始化)。正确的处理方法是什么? 我还尝

  • 问题内容: 我的结构如下所示: 组件3应该根据组件5的状态显示一些数据。由于道具是不可变的,我不能简单地将其状态保存在组件1中并转发它,对吗?是的,我已经阅读了有关redux的内容,但不想使用它。我希望有可能通过反应来解决。我错了吗? 问题答案: 对于孩子与父母的通信,您应该传递一个将状态从父母设置为孩子的函数,如下所示 这样,孩子可以通过调用通过props传递的函数来更新父母的状态。 但是您将不

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