Redux - 为什么州都在一个地方,甚至是非全球的州?

时间:2016-02-27 01:23:18

标签: javascript reactjs redux

我是React的新手,甚至是Redux的新手。到目前为止,我们已经将它们一起用于小型沙箱应用程序,我喜欢它们。

但是,当谈到更大的应用程序时,我开始怀疑这个: 为什么Redux会将您的整个应用程序状态保存在一个商店中?

如果我有一个包含许多不同部分的应用程序(并且每个部分都有自己的组件),那么将每个部分的状态保持为自己(在每个部分的顶级组件中)是有意义的,只要他们的状态不影响其他组件的东西。

我不确定将状态统一在一个地方的好处,当那个状态的部分与其他部分没有任何关系时。如果组件A不受组件B状态的影响,反之亦然,它们的状态不应该保存在它们的组件中而不是保存在根组中吗?

我不能在根目录中拥有影响全局的状态,以及特定于自己组件中每个组件的状态吗?我担心将链中的所有特定于组件的状态一直抛到全局状态对象(特别是当React强调自上而下的流时)。

2 个答案:

答案 0 :(得分:12)

用户界面应用程序的全局状态的主要优点是您可以在原始状态下跟踪整个应用程序的状态更改。

tldr;你可以随时轻松保存和预测应用程序的状态,因为只有一个事实来源。

自我管理组件的问题在于它们会创建一个不可预测的可能状态组合。如果XComponent改变自己,你不能轻易告诉你的应用程序将处于什么状态,因为你必须纠缠YComponent和ZComponent,然后让他们知道彼此的状态,以便他们根据这个状态做出决定并确定状态。整体申请。

这真正归结为背景。如果我的决定依赖于知道应用程序状态的3个独立部分的状态,这些部分在UI组成方面没有直接关系,那么如何让上下文做出决策并将结果传达回整个应用程序?如果没有完整的状态表示,就没有简单的方法可以获得上下文聚合。

Redux(和Reagent中的ratom等其他模式)通过全局统一状态解决了这个问题。您的操作只是状态更改的信使,但您的商店是上下文持有者。没有一个商店,你的组件就像封建军阀在他们松散相关的封地状态上争吵。商店是一个紧密结合的寡头集团(\b([a-zA-Z]+)\b\s(\d+) )的结果,它用铁拳统治你的申请状态并防止错误:)

全局状态适用于UI并解决了很多问题,即使这对其他类型的软件来说是违反直觉的,甚至是不好的做法。也就是说,经常注意到并非所有应用程序状态都需要在Redux存储中。此外,您可以清除不再有用/相关的数据。最后,只与给定组件相关的状态(以及它的行为/显示)不需要反映在全局存储中(必然)。

Redux中的关注分离抽象是reducer,因为您可以创建多个reducer并将它们组合在一起,为商店更新创建逻辑链。

使用reducers,你仍然在代码中“分离”你的状态逻辑,但实际上它在运行时都被视为一棵树。这可以保持您的状态变化可预测和原子化,但允许良好的组织,封装和关注点分离。

答案 1 :(得分:10)

为什么我们将持久状态转移到数据库中,而不是让每个后端组件在单独的文件中管理它们的状态?

因为它可以更轻松地查询,调试和序列化我们的整体应用程序状态。

Redux的灵感来自于一种名为Elm的语言,它也促进了单一模型的使用。榆树的创作者进一步证明了为什么这是一个重要的应用质量。

  

有一个单一的事实来源。传统方法迫使您编写大量自定义和容易出错的代码,以在许多不同的有状态组件之间同步状态。 (此小部件的状态需要与应用程序状态同步,需要与其他小部件同步等。)通过将所有状态放在一个位置,可以消除整个类别的错误,其中两个组件得到进入不一致的状态。我们还认为您最终会编写更少的代码。到目前为止,这是我们在Elm的观察。

我发现这个概念更容易学习和理解,同时从ClojureScript Re-frame处理它并观看David Nolen的videos on Om Next。该项目的Re-frame README也是一个很好的学习资源。

以下是我个人对于为什么全球国家是一个更优雅的解决方案的看法。

更简单的组件

许多基于状态组件的应用程序中出现的常见情况是需要修改位于另一个组件中的状态。

例如,单击NameTag组件中的编辑按钮应打开一个编辑器,允许用户修改一些生成Profile组件状态的数据(NameTag的父级1}})。解决此问题的方法是传递处理程序回调,然后将数据传播回组件树。这种模式导致React应用程序的现有单向数据流中的子数据流混乱。

对于全局状态,组件只调度触发该状态更新的操作。可以参数化组件和操作以将上下文信息发送回用户(例如,我正在编辑其名称的用户的ID)。

您不必考虑如何将状态更改传达给状态,因为您确切知道状态的位置,而操作是在那里发送这些更改的预定义机制。 / p>

纯函数

当您的应用程序状态位于单个位置时,呈现它的组件可以是以状态作为参数的纯函数。他们只是查看数据,并返回一个可以调度操作以进行更新的视图。

这些函数是引用透明的,这意味着对于任何给定的输入集,总会有完全相同的输出。这是测试的理想选择,您最终会得到直接测试的组件。

序列化

在具有有状态组件的传统React应用程序中,序列化整个应用程序状态将是一场噩梦。它将涉及遍历整个组件树并从每个组件中提取状态值,然后将它们全部收集在数据结构中并对其进行编码。

使用序列化状态重新充气组件意味着类似的过程,除了您还需要确定哪些类型的组件负责哪些数据,以便您可以准确地重新创建组件树。这也意味着存储有关您所在州的组件类型的其他信息。

使用全局状态,您可以简单地对其进行编码和解码。

撤消/重做

要实现具有全局状态的撤消/重做,您需要在列表中存储状态,而不是在更新时替换最后一个状态。索引指针可以控制您当前的状态。

对于有状态组件,这将要求每个组件实现此机制。这不仅是一项额外的工作,而且还会在您的应用程序中创建另一个引入错误的点。正如他们所说,最好的代码是没有代码。

动作播放

在Redux(以及一般的Flux模式)中,我们可以跟踪已经播放的动作,然后在另一个上下文中播放它们以产生完全相同的状态。

如果你介绍组件本地状态,那么你可以告别它。对本地状态的更新可以来自DOM事件处理程序,网络请求,异步操作(以及更多)。这些操作无法序列化,这意味着它们也无法播放。