Redux: 为什么不能改变状态...

创建于 2015-09-20  ·  13评论  ·  资料来源: reduxjs/redux

你好

我感兴趣地阅读了有关不可变的知识,以及您不应该如何改变状态的知识。 我在某种程度上理解了为什么会这样,但是,我对“花费在创建新对象上的时间感到担忧”方面不是在JS中不了解这是快/慢,还是我错过了其他东西。

通常,创建一个新对象,或多或少地将一个旧对象克隆到新对象,再加上新的状态加法(或减法),这似乎比仅修改现有状态要花费更多的时间。 因此,我试图理解为什么不变的事物如此重要,并且会影响到我所没有看到的链下其他事物吗?

此外,我认为Reduct提供的很多功能都可以添加到react-core中,甚至可以利用其DOM差异引擎...甚至可以帮助确定状态是否应该改变。 我不确定更改状态的过程是否比将状态与新状态扩散并仅更改(更改)应更改的实际状态对象的部分更快或更慢?

对于这一切我都比较陌生,所以如果我遗漏了不改变状态这一概念,请原谅我。 我确实很喜欢这样的想法,即组件应该只呈现不可变的数据...但是,再次,对于该组件,它不在乎或不知道其不可变的..它只是从某个地方传入的数据,所以我在努力整个不可变与可变状态。

question

最有用的评论

需要说明的是:状态并非在每个动作上都被深深地克隆。 仅克隆已更改的部分(再次(不是很深入),取决于已更改的内容)。 例如,当在TodoMVC应用程序中编辑待办事项时,仅克隆该待办事​​项对象。 其余的todo对象相同。 当然,会创建一个新的根待办事项列表数组,指向新对象,但是如果对象本身没有更改,则不会克隆它们本身。 因此,它并不像看起来那样昂贵。 此外,当它变得昂贵(例如快速更改数组)时,您可以开始使用Immutable.js之类的库,该库由于结构共享而具有非常快的复制速度。 使用Immutable.js,即使复制大型数组也不是那么昂贵,因为可以重用大量内存。 最后,无论是否具有Immutable.js,不变性都可以帮助我们有效地重新渲染应用程序,因为我们知道由于对象未发生突变,确切地改变了什么。

所有13条评论

一切都与可预测性和可靠性有关。

redux中的reducer是纯函数,这意味着它们没有副作用。 一旦您开始查看这些功能的某些外部状态,它们就不再是纯粹的。 如果它们不是纯净的,它们可能会不可靠。 这会导致错误,很多错误很难被发现。

通过编写纯函数,我发现我的代码产生的错误更少,而且效率更高。 热模块重装(通过使用纯功能启用)是提高生产力的涡轮增压器。

而且,您可以免费获得免费的功能,例如时间旅行。

以#328的副本形式关闭。

需要说明的是:状态并非在每个动作上都被深深地克隆。 仅克隆已更改的部分(再次(不是很深入),取决于已更改的内容)。 例如,当在TodoMVC应用程序中编辑待办事项时,仅克隆该待办事​​项对象。 其余的todo对象相同。 当然,会创建一个新的根待办事项列表数组,指向新对象,但是如果对象本身没有更改,则不会克隆它们本身。 因此,它并不像看起来那样昂贵。 此外,当它变得昂贵(例如快速更改数组)时,您可以开始使用Immutable.js之类的库,该库由于结构共享而具有非常快的复制速度。 使用Immutable.js,即使复制大型数组也不是那么昂贵,因为可以重用大量内存。 最后,无论是否具有Immutable.js,不变性都可以帮助我们有效地重新渲染应用程序,因为我们知道由于对象未发生突变,确切地改变了什么。

啊....现在看到最后一点是有意义的...我假设您是说,由于仅由于更改了什么状态而导致组件渲染更改,结果是,响应差异/重绘引擎更快吗? 我猜应该类似于shouldComponentUpdate

我假设您是说由于组件渲染仅由于什么状态改变而改变,结果是响应差异/重绘引擎更快? 我猜应该类似于shouldComponentUpdate

确切地说,由于不可变性保证, react-redux在后台使用了激进的shouldComponentUpdate

@gaearon对不起,对此死了一点! 但是您对快速数组更新的评论:

此外,当它变得昂贵(例如快速更改数组)时,您可以开始使用Immutable.js之类的库,该库由于结构共享而具有非常快的复制速度。

我正在使用redux来处理对多达8000个位置的阵列的更新,并期望吞吐量在每100ms 10-100次更改的范围内。 我是否正在努力尝试使用redux来管理状态的失败之战?
我们计划通过画布而不是DOM来表示状态,但是我想了解一下,根据您的经验,更新频率是否会给我们带来麻烦。

@dougajmcdonald :我的第一个问题是,可以通过某种方式来整理其中的任何作品吗? 您是否真的需要将每个单独的更新表示为UI的单独重绘?

除此之外,我建议您查看有关Redux相关性能的以下资源:

我也很乐意在Reactiflux聊天频道中谈论更多。

@markerikson不幸的是,游戏的概念涉及到相对较大数据结构的许多快速更新。
我意识到我的原始评论并不完全清楚,当我说10-100次更改时,这些不会全部触发重画。 10-100次更改是状态更改,将通过每100ms一次重绘来表示。
所以我的问题是,如果我将每100ms的更新分为10-100个状态更改,redux中的状态管理是否可以有效地处理这些更新,并在100ms的类似窗口内完成。允许重画而事情不会落伍。
状态更新基本上涉及更改大小为8000的数组中的3-4个属性,因此我们要谈论的是每毫秒创建1-10次新数组(假设我们希望保持不变),并对其中一个进行一些更改数组索引中的对象。 对象很小(3-4个属性,几个数字和几个小字符串)

这就是为什么我想知道像Dan所建议的那样使用不可变的好处,好像我们可以重用尽可能多的数组,这可能会提高性能。

@dougajmcdonald :好吧,“ Redux中的状态管理”实际上只是_root提供的一个root reducer函数:)

Immutable.js并不是改进性能的神奇子弹。 它可以使某些事情变快,而另一些事情变慢。 我有多篇关于Immutable.js的perf注意事项的文章,您可能想看看。

坦白说,考虑到您的用例,如果您愿意,理论上您可以更多地摆脱直接突变。 根据我的文章Idiomatic Redux,第1部分-实现和意图,Redux核心本身实际上根本不关心突变-它主要是React-Redux UI层以及DevTools。 现在,突变并不是您想要使用Redux的方式,但是有可能。

我个人的建议是从简单开始。 只需使用普通的JS对象和数组即可。 通过“手动”或使用许多不可变的更新实用程序库之一来

然后,从那里,您可以在批处理,减少调度,更新逻辑等方面进行其他优化工作。

鼻子上有@markerikson微妙的
感谢关于不变性的观点和关于直接突变的观点,我会读一点并考虑这些。
目前,我的思想过程是断开redux状态与画布的连接,并通过pub / sub(这是我们已经将其连接起来的方式)传递消息的方式,同时使用更多的移动部件

我正在考虑从:
pubsub> dispatch()> reducer> Redux状态> React组件内容> canvas渲染。

至:
pubsub>本地组件状态> canvas渲染

我仍将在UI的其余部分使用redux,也许不是应用程序的画布部分。

您的问题是完全有效的。 实际上,称为vuex的redux的vuejs实现在突变概念下工作。 因此,“减少者”实际上称为突变,只要您在集中位置修改状态,一切都应该没问题。 发生这种情况是因为vue在应用程序的状态中添加了观察者和其他内容,因此正如您所提到的,在vue的范围内修改而不是替换对象更有意义。 Redux是不可变的,最后两种方法的性能都响应VS vue虚拟DOM更新在大多数情况下是相同的,这不可能说在所有情况下都优于另一种

此页面是否有帮助?
0 / 5 - 0 等级