Reducer Composition - 为什么我们需要重新分配todos with Object.assign()为什么不调用另一个reducer呢?

时间:2017-02-27 21:55:06

标签: javascript functional-programming redux react-redux

在这个减速器组成示例的情况下,为什么我们不能只返回我们调用的减速器?这意味着,在todoAppADD_TODO的{​​{1}}缩减器中,我们使用的是另一个缩减器:TOGGLE_TODO。我明白那个。但我不明白为什么我们不能将todos中的案例设为

todoApp

vs我们在这里:

function todoApp(state = initialState, action) {
  switch (action.type) {
    case ADD_TODO:
    case TOGGLE_TODO:
      return todos(state.todos, action)

特别是因为todos reducer正在返回全新的状态对象,对吧?我们是不是仍然遵循redux规则而不是通过返回第二个reducer的结果来修改状态?

function todoApp(state = initialState, action) {
  switch (action.type) {
    case ADD_TODO:
    case TOGGLE_TODO:
       return Object.assign({}, state, {
         todos: todos(state.todos, action)
       })

2 个答案:

答案 0 :(得分:3)

你问为什么这个

case TOGGLE_TODO:
  return Object.assign({}, state, {
    todos: todos(state.todos, action)
  })

......不能只是这个......

case TOGGLE_TODO:
  return todos(state.todos, action)

你必须注意你正在使用的reducer的特定上下文中的状态的形状

  • todo的状态为[Todo] - 其中[Todo]是待办事项的数组

  • todoApp的状态为{todos: [Todo]}

如果您要使用建议的代码

case TOGGLE_TODO:
  return todos(state.todos, action)

知道todos将返回[Todo],您将取代todoApp州......

{todos: [Todo]}

...与

[Todo]

......这不是正确的形状。

  

所以如果形状相同,那就没关系,否则我不会修改状态,对吗? - Anna Garcia 25分钟前

正确,但他们在这种情况下使用Object.assign的原因是一种前瞻性的最佳做法。

你可以做到

case TOGGLE_TODO:
  return {todos: todos(state.todos, action)}

但是,有理由认为您的应用程序将具有其需要关注的其他“切片”状态 - 而不是只是 todos。在这种情况下,TOGGLE_TODO操作仅对todos切片起作用。谨慎地更新todos的方式不会破坏此上下文中的所有其他现有属性。

因此,假设我们的应用程序还有另外两个状态切片,foobar。如果我们这样做......

// where state = {foo: 1, bar: 2, todos: [ ... ]}
case TOGGLE_TODO:
  return {todos: todos(state.todos, action)}

然后我们只返回{todos: ...} - foobar属性/值已被删除!不好!<​​/ p>

相反,我们必须小心保留其他状态条目,对我们打算修改的状态进行操作

// where state = {foo: 1, bar: 2, todos: [ ... ]}
case TOGGLE_TODO:
  return Object.assign({}, state, {todos: todos(state.todos, action)})

现在我们将回来

{foo: 1, bar: 2, todos: newTodosArray}

这正是我们想要的 - 所有foobartodos属性仍处于todoApp状态。

对象传播语法

有一项建议支持对象的扩展语法,这可以将Object.assign示例简化为

case TOGGLE_TODO:
  return {...state, todos: todos(state.todos, action)}

但是直到它进入ECMAScript,你将不得不使用transform-object-rest-spread

进行babelify

答案 1 :(得分:0)

redux的主要概念是你永远不能直接修改状态,你必须返回一个新的状态。您提出的解决方案是修改当前状态,这是不允许的。

  

特别是因为todos reducer正在返回全新的状态   对象,对吗?1

这里的关键词是'新'。它必须是一个新的状态对象,而不是对当前对象的修改。