为什么Redux示例将空对象作为第一个Object.assign()参数传递?

时间:2015-11-20 13:46:06

标签: javascript reactjs redux

redux project的todoMVC示例中,用于处理待办事项的reducer有以下几行:

export default function todos(state = initialState, action){
    ...
    case EDIT_TODO:
      return state.map(todo =>
        todo.id === action.id ?
          Object.assign({}, todo, { text: action.text }) :
          todo
      )
}

此部分代码涉及更新特定的待办事项。我的问题是,因为state.map()将始终返回一个新数组。然后,还有必要这样做:

Object.assign({}, todo, { text: action.text})

可以这样:

Object.assign(todo, { text: action.text})

更新

我理解Object.assign({}, blah...)Object.assign(obj, blah...)之间的区别。让我重新解释一下我的问题:

Redux希望reducer返回一个新状态而不是改变现有状态。我知道了。在我的例子中,我有一个对象数组。我想交换前两个元素的顺序。查看jsbin example here

  1. 由于 Array.map 始终返回新数组,因此对返回数组的引用将被设为新数组。检查。
  2. 但是,返回数组中的元素不是全新。对前两个元素的引用是新的。但是,第三项不是。它与旧数组中的第三项相同。
  3. 所以我的问题是第三个元素,我应该使用:

    Object.assign({}, third_element)或只是return the third_elment

    Redux是否需要一个新的数组,其中包含对其中每个对象的新引用(即使存储在这些新对象中的值与旧对象相同),还是仅仅是一个只有新更新元素的新数组?

3 个答案:

答案 0 :(得分:15)

这是Object.assign的工作原理。它返回目标对象作为其操作的返回值。所以,在第一种语法中:

Object.assign({}, todo, { text: action.text})

您正在使用todo{ text: action.text}的可枚举属性创建一个全新的对象。

如果你这样做:

Object.assign(todo, { text: action.text})

然后todo本身就是目标对象,因此将会发生变异,这将是从Object.assign返回的内容。

第一种方法是通过创建一个全新对象的新数组使地图操作完全不可变。

这是一个说明我的意思的jsbin。请注意,在第一个示例中,数组中的原始对象已更改,这意味着状态已发生变异。在第二个中,原始对象保持不变:

https://jsbin.com/boxeserave/edit?html,js,console

答案 1 :(得分:6)

来自Dan Abramov(Redux的创造者)的推文:

  

Common Redux误解:你需要深度克隆状态。现实:如果里面的东西没有改变,保持它的参考相同!

https://twitter.com/dan_abramov/status/688087202312491008

答案 2 :(得分:3)

我想补充一下这个很好的答案并解释为什么需要从Object.assign返回一个新对象。

使用redux的工作方式,如果reducer返回state参数中收到的相同引用,则redux将假定状态未更改并且不会更新视图。为了告诉redux你正在改变状态,你必须返回一个新的引用。这就是为什么您总会在减速器中看到一个新的空对象{}作为Object.assign的第一个参数。