为什么Redux中的对象应该是不可变的?

bor*_*net 32 javascript immutability reactjs redux angular

为什么Redux中的对象应该是不可变的?我知道一些框架如Angular2将使用onPush并且可以利用不变性来比较视图状态以便更快地呈现,但我想知道是否还有其他原因因为Redux是框架无关的,但它在自己的文档中提到使用不变性(无论框架如何).

感谢任何反馈.

Ash*_*man 28

Redux是一个小型库,它将状态表示为(不可变)对象.和新的状态通过使当前状态通过纯函数来创建一个全新的对象/应用程序状态.

如果你的眼睛釉面那边不用担心.总而言之,Redux不会通过修改对象来表示应用程序状态的变化(就像使用面向对象的范例一样).相反,状态更改表示为输入对象和输出对象()之间差异var output = reducer(input).如果你改变了,input或者output你使状态无效.

总结另一种方式,不变性是Redux的要求,因为Redux将您的应用程序状态表示为"冻结对象快照".使用这些离散快照,您可以保存状态或反向状态,并且通常对所有状态更改具有更多"记帐".

您的应用状态由称为reducer的纯函数类别更改.减速器有两个重要特性:

  1. 它们从不变异,返回新构建的对象:这允许推理输入+输出而没有副作用
  2. 他们的签名总是 function name(state, action) {}如此,因此可以很容易地编写它们:

假设状态如下:

    var theState = {
      _2ndLevel: {
        count: 0
      }
    }
Run Code Online (Sandbox Code Playgroud)

我们想增加计数,所以我们制作这些减速器

const INCR_2ND_LEVEL_COUNT = 'incr2NdLevelCount';

function _2ndlevel (state, action) {
    switch (action.type) {
        case INCR_2ND_LEVEL_COUNT:
            var newState = Objectd.assign({}, state);
            newState.count++
            return newState;
        }
    }

function topLevel (state, action) {
    switch (action.type) {
        case INCR_2ND_LEVEL_COUNT:
            return Objectd.assign({}, {_2ndLevel: _2ndlevel(state._2ndlevel)});
    }
}
Run Code Online (Sandbox Code Playgroud)

注意使用Objectd.assign({}, ...)每个 reducer中创建一个全新的对象:

假设我们已将Redux连接到这些Reducer,那么如果我们使用Redux的事件系统来触发状态更改......

    dispatch({type: INCR_2ND_LEVEL_COUNT})
Run Code Online (Sandbox Code Playgroud)

... Redux将致电:

    theNewState = topLevel(theState, action);
Run Code Online (Sandbox Code Playgroud)

注意:action来自dispatch()

现在theNewState是一个全新的对象.

注意:您可以使用(或新语言功能)强制实现不变性,或者只是小心不要改变任何内容:D

为了更深入一点,我强烈建议您查看Dan Abramov(创作者)的视频.它应该回答你有任何挥之不去的问题.

  • 我不知道这是如何回答"为什么国家应该是不可改变的"这个问题.是的,它解释了很多如何做,只是重复Redux规范:"状态应该是不可变的",但没有描述/解释它背后的动机.如果应用程序状态有任何理由来描述转换(更改),那么只需在任何纯函数调用之前和之后生成**Objectd.assign({},...)**. (8认同)
  • 首先让我说谢谢你的回答,我给你+1.但有了这个,让我解释一下,我非常清楚Redux是如何工作的,我已经使用过了,我的问题是深思熟虑的.想想看,如果您更改名称而不是替换保存名称的整个对象,您仍然可以实现"冻结对象快照".唯一的原因(这可能是一个足够好的理由)是速度比较.因为在冻结状态时比较新对象与更改对象可能会更快.这将是我能看到的唯一原因... tx Sean. (5认同)
  • 啊,好吧 - 哎呀:P。嗯,我不明白当您更改名称时如何实现“冻结对象快照”,因为您随后更改了对象。但无论如何,我认为你走在正确的道路上。对不变性的关注是因为典型 SPA 中发生的_计算经济学_有助于浅层/哑对象比较重新创建状态。想象一下,您修改的不是一个名称,而是渲染表中 1000 行的单个单元格中的名称。当_某些_发生变化时重新渲染表比遍历整个状态以找出_确切发生了什么_变化要快。 (2认同)
  • @ErezCohen如果您对某个对象的内部进行突变,则该对象仍然相同-因此,redux进行的廉价比较不会注意到这一变化。您需要返回一个新的顶级对象。https://facebook.github.io/immutable-js/是强制执行此操作的一种方法。 (2认同)

And*_*cia 10

Redux文档中提到了不可变性的以下好处:

  • Redux和React-Redux都采用浅层相等检查.特别是:
  • 不可变数据管理最终使数据处理更安全.
  • 时间旅行调试要求减速器是纯函数,没有副作用,因此您可以在不同状态之间正确跳转.


小智 9

Redux 使用不变性的主要原因是它不必遍历对象树来检查每个键值的更改。相反,它只会检查对象的引用是否更改,以便在状态更改时更新 DOM。