Reducer Composition - 为什么我们需要用 Object.assign() 重新分配待办事项,为什么不直接调用另一个 reducer?
Reducer Composition - why do we need to re assign todos with Object.assign() why not just call the other reducer?
在这个 reducer 组合示例中,为什么我们不能 return 我们正在调用的 reducer?意思是,在 todoApp
减速器中,在 ADD_TODO
或 TOGGLE_TODO
的情况下,我们使用另一个减速器:todos
。我明白那个。但我不明白为什么我们不能将 todoApp
中的大小写设置为
function todoApp(state = initialState, action) {
switch (action.type) {
case ADD_TODO:
case TOGGLE_TODO:
return todos(state.todos, action)
与我们这里的对比:
function todoApp(state = initialState, action) {
switch (action.type) {
case ADD_TODO:
case TOGGLE_TODO:
return Object.assign({}, state, {
todos: todos(state.todos, action)
})
特别是因为 todos reducer 正在 returning 完整的新状态对象,对吧?我们不是仍然遵循 redux 规则而不是通过 returning 第二个 reducer 的结果来修改状态吗?
function todos(state = [], action) {
switch (action.type) {
case ADD_TODO:
return [
...state,
{
text: action.text,
completed: false
}
]
case TOGGLE_TODO:
return state.map((todo, index) => {
if (index === action.index) {
return Object.assign({}, todo, {
completed: !todo.completed
})
}
return todo
})
default:
return state
}
}
function todoApp(state = initialState, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return Object.assign({}, state, {
visibilityFilter: action.filter
})
case ADD_TODO:
case TOGGLE_TODO:
return Object.assign({}, state, {
todos: todos(state.todos, action)
})
default:
return state
}
}
redux 的主要概念是你永远不能直接修改状态,你必须 return 一个新的状态。您提出的解决方案是修改当前状态,这是不允许的。
Especially since the todos reducer is returning the full new state
object, right?1
他们这里的关键词是'new'。它必须是一个新的状态对象,而不是对当前状态对象的修改。
你问的是为什么
case TOGGLE_TODO:
return Object.assign({}, state, {
todos: todos(state.todos, action)
})
...不能只是这样...
case TOGGLE_TODO:
return todos(state.todos, action)
你必须注意你正在使用的减速器的特定上下文中的状态形状
todo
的状态形状为 [Todo]
– 其中 [Todo]
是 todos[=45 的 Array =]
todoApp
的状态形状为 {todos: [Todo]}
如果您要使用建议的代码
case TOGGLE_TODO:
return todos(state.todos, action)
知道 todos
将 return [Todo]
,您将替换您的 todoApp
状态 ...
{todos: [Todo]}
...与
[Todo]
...这不是正确的形状。
So if the shape were the same this would be ok, I wouldn't be modifying the state otherwise, correct? – Anna Garcia 25 mins ago
正确,但他们在这种情况下使用 Object.assign
的原因是具有前瞻性的最佳实践。
你可以做到
case TOGGLE_TODO:
return {todos: todos(state.todos, action)}
但是,有理由认为您的应用程序需要关注其他 "slices" 状态 – 而不仅仅是 todos
。在这种情况下,TOGGLE_TODO
操作仅作用于 todos
切片。请注意以不会破坏此上下文中所有其他现有属性的方式更新 todos
。
假设我们的应用程序有另外两个状态片段,foo
和 bar
。如果我们这样做...
// where state = {foo: 1, bar: 2, todos: [ ... ]}
case TOGGLE_TODO:
return {todos: todos(state.todos, action)}
那么我们只 returning {todos: ...}
– foo
和 bar
properties/values 已被删除!不好!
相反,我们必须小心保留其他状态条目,并且仅对我们打算修改的状态进行操作
// 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}
这正是我们想要的——所有 foo
、bar
和 todos
属性仍处于 todoApp
状态。
对象传播语法
有人提议支持对象的扩展语法,这可以将 Object.assign
示例简化为
case TOGGLE_TODO:
return {...state, todos: todos(state.todos, action)}
但在它进入 ECMAScript 之前,您必须使用 transform-object-rest-spread
对其进行 babelify
在这个 reducer 组合示例中,为什么我们不能 return 我们正在调用的 reducer?意思是,在 todoApp
减速器中,在 ADD_TODO
或 TOGGLE_TODO
的情况下,我们使用另一个减速器:todos
。我明白那个。但我不明白为什么我们不能将 todoApp
中的大小写设置为
function todoApp(state = initialState, action) {
switch (action.type) {
case ADD_TODO:
case TOGGLE_TODO:
return todos(state.todos, action)
与我们这里的对比:
function todoApp(state = initialState, action) {
switch (action.type) {
case ADD_TODO:
case TOGGLE_TODO:
return Object.assign({}, state, {
todos: todos(state.todos, action)
})
特别是因为 todos reducer 正在 returning 完整的新状态对象,对吧?我们不是仍然遵循 redux 规则而不是通过 returning 第二个 reducer 的结果来修改状态吗?
function todos(state = [], action) {
switch (action.type) {
case ADD_TODO:
return [
...state,
{
text: action.text,
completed: false
}
]
case TOGGLE_TODO:
return state.map((todo, index) => {
if (index === action.index) {
return Object.assign({}, todo, {
completed: !todo.completed
})
}
return todo
})
default:
return state
}
}
function todoApp(state = initialState, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return Object.assign({}, state, {
visibilityFilter: action.filter
})
case ADD_TODO:
case TOGGLE_TODO:
return Object.assign({}, state, {
todos: todos(state.todos, action)
})
default:
return state
}
}
redux 的主要概念是你永远不能直接修改状态,你必须 return 一个新的状态。您提出的解决方案是修改当前状态,这是不允许的。
Especially since the todos reducer is returning the full new state object, right?1
他们这里的关键词是'new'。它必须是一个新的状态对象,而不是对当前状态对象的修改。
你问的是为什么
case TOGGLE_TODO:
return Object.assign({}, state, {
todos: todos(state.todos, action)
})
...不能只是这样...
case TOGGLE_TODO:
return todos(state.todos, action)
你必须注意你正在使用的减速器的特定上下文中的状态形状
todo
的状态形状为[Todo]
– 其中[Todo]
是 todos[=45 的 Array =]todoApp
的状态形状为{todos: [Todo]}
如果您要使用建议的代码
case TOGGLE_TODO:
return todos(state.todos, action)
知道 todos
将 return [Todo]
,您将替换您的 todoApp
状态 ...
{todos: [Todo]}
...与
[Todo]
...这不是正确的形状。
So if the shape were the same this would be ok, I wouldn't be modifying the state otherwise, correct? – Anna Garcia 25 mins ago
正确,但他们在这种情况下使用 Object.assign
的原因是具有前瞻性的最佳实践。
你可以做到
case TOGGLE_TODO:
return {todos: todos(state.todos, action)}
但是,有理由认为您的应用程序需要关注其他 "slices" 状态 – 而不仅仅是 todos
。在这种情况下,TOGGLE_TODO
操作仅作用于 todos
切片。请注意以不会破坏此上下文中所有其他现有属性的方式更新 todos
。
假设我们的应用程序有另外两个状态片段,foo
和 bar
。如果我们这样做...
// where state = {foo: 1, bar: 2, todos: [ ... ]}
case TOGGLE_TODO:
return {todos: todos(state.todos, action)}
那么我们只 returning {todos: ...}
– foo
和 bar
properties/values 已被删除!不好!
相反,我们必须小心保留其他状态条目,并且仅对我们打算修改的状态进行操作
// 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}
这正是我们想要的——所有 foo
、bar
和 todos
属性仍处于 todoApp
状态。
对象传播语法
有人提议支持对象的扩展语法,这可以将 Object.assign
示例简化为
case TOGGLE_TODO:
return {...state, todos: todos(state.todos, action)}
但在它进入 ECMAScript 之前,您必须使用 transform-object-rest-spread
对其进行 babelify