ReactJS:为什么我不应该改变嵌套状态?

IT技术 reactjs
2021-05-23 22:42:32

我已经阅读了关于setState的 ReactJS 文档具体来说,这一行:

永远不要直接改变 this.state,因为之后调用 setState() 可能会替换你所做的改变。将 this.state 视为不可变的。

但在我的代码中,我做这样的事情:

var x = this.state.x;
x.y.z.push("foo"); // z is a list
this.setState({x:x});

此代码似乎可以正常工作并正确更新状态。但是根据文档,我违反了规则。这种方法有什么问题?是否存在性能问题?比赛条件?我会被 Facebook 开发团队骂吗?理想情况下,我想避免不变性助手和所有其他疯狂并保持简单。

3个回答

通过直接操作状态,您可以绕过 React 的状态管理,这确实与 React 范式背道而驰。React 最显着的好处setState是它会立即触发重新渲染,这会将您的 DOM 更改从 shadow DOM 合并到文档 DOM 中。因此,您可以在某个处理程序中捕获您需要的所有状态更改,然后在文字对象中构建您想要的状态更改,然后将其传递给setState. 这不是你上面的例子所做的。

因此,虽然您提供的代码示例在技术上打破了这条规则,但由于您setState在通过对状态对象属性的引用进行变异后直接调用,因此您的更改会立即通过 React 的状态管理传递。所以,一切都会如你所愿。这个想法是,您不想养成以这种方式对状态进行多次更改的习惯,最好在新的文字对象或数组中捕获您想要的状态,然后将其设置为该状态一次(即,使用没有先前的状态突变)通过调用setState,这将触发一次重新渲染。

编辑:为了更明确地回答你的问题,我想补充一点,真正关心的是开发人员会在许多不同的地方或方法中直接操纵状态,而无需调用setState,然后在稍后的某个时间点或其他代码,调用setState然后想知道为什么他们的render 没有产生他们预期的结果。由于setState对象在已知的托管状态和作为参数传递给 的文字对象之间合并setState,因此如果您之前直接操作状态,结果可能与您期望的不同。

原因是你错过了与之相关的回调this.setState,他们声称你可以通过直接分配给对象来覆盖数据。

此外,通常在 OOP 中(我不知道 JS 获得了多少颗星...)您将使用 getter 和 setter 方法,而不是直接操作对象。在这个例子中通过this.state.prop1 = "xyz";

我从来没有react覆盖我直接设置的状态属性。以这种方式编码的诱惑可能是在不重新渲染的情况下写入状态。但是如果你这样做,你可能会考虑不把它们放在 state 中。

如果重新渲染性能是一个问题,请查看https://facebook.github.io/react/docs/component-specs.html#updating-shouldcomponentupdate

主要原因是 shouldComponentUpdate 不能正常工作。