在 Redux egghead.io 系列的第 16 课中,我尝试实现自己的 combineReducers 函数,然后再看 Dan 是如何做到的。我得到了以下几点。我试图在子减速器(todos
,visibilityFilter
)上使用for ... in
,就像这样传入
const combineReducers = (reducers) => {
return (state,action) => {
let temp = {};
for (let i in reducers) {
temp[i] = reducers[i](state,action)
}
return temp;
}
}
这行不通。当我使用预期库对其进行测试时,我在控制台中收到以下错误。奇怪的是,如果我没记错的话,看起来从调用到todos
化简器的状态已经嵌套到visibilityFilter
化简器的调用中。这很奇怪,因为我的代码显示它们是返回的对象中明显独立的字段。
未捕获的错误: 预期 { 待办事项: [ { 已完成: 假, id: 1, 文本: '去购物' } ], 可见性过滤器: { 待办事项: [ { 已完成: 假, id: 0, 文本: 'Learn Redux' } ], visibilityFilter: 'SHOW_ALL' } } to 等于 { 待办事项: [ { 已完成: 假, id: 0, 文本: 'Learn Redux' }, { 已完成:假,ID:1,文本:"去购物"} ],可见性过滤器: 'SHOW_ALL' }
我的测试代码是
const testTodoApp = () => {
const stateBefore = {
todos: [{id: 0, text:'Learn Redux', completed: false}],
visibilityFilter: 'SHOW_ALL',
};
// action is an object. with a defined type property.
const action = {
type: 'ADD_TODO',
id: 1,
text: 'Go shopping',
};
const stateAfter = {
todos: [{id: 0, text:'Learn Redux', completed: false},
{id: 1, text:'Go shopping', completed: false},
],
visibilityFilter: 'SHOW_ALL',
};
deepFreeze(stateBefore);
deepFreeze(action);
expect(
todoApp(stateBefore, action)
).toEqual(stateAfter);
console.log("Test passed: todoApp")
}
testTodoApp();
如果我使用内置的组合减速器,此测试将通过。子减速器和调用combineReducers
如下:
const todo = (state = {} ,action) => {
switch (action.type) {
case 'ADD_TODO':
return {
id: action.id, text: action.text, completed: false,
};
case 'TOGGLE_TODO':
if (state.id !== action.id) {
return state;
}
return {
...state, completed: !state.completed,
};
default:
return state;
}
}
const todos = (state=[], action) =>{
switch (action.type) {
case 'ADD_TODO':
console.log('ADD_TODO switch selected')
return [
...state,
todo(undefined,action),
];
case 'TOGGLE_TODO':
console.log('TOGGLE_TODO switch selected')
return state.map( t => todo(t, action))
default:
console.log('default switch selected')
return state;
}
}
const visibilityFilter = (
state = 'SHOW_ALL',
action
) => {
switch (action.type) {
case 'SET_VISIBILITY_FILTER':
return action.filter;
default:
return state;
}
}
const todoApp = combineReducers({
todos,
visibilityFilter,
})
我的问题是:
- 我的代码中是什么导致一个化简器嵌套在另一个化简器中?
- 我意识到 Dan 改用了
reduce
,但出于教学原因,我如何使用for ... in
模式来实现组合化简器? - 之后,您能否评论一下将
for ... in
用于此类应用程序的适当性,如果这是一个糟糕的模式,是什么让它如此?
我刚刚意识到todos
化简器和visibilityFilter
化简器必须传递与其键对应的组合状态部分,而不是整个组合状态。所以工作代码应该看起来像这样,我在第 5 行的状态的相应部分添加了一个对象访问器。
const combineReducers = (reducers) => {
return (state,action) => {
let temp = {};
for (let i in reducers) {
temp[i] = reducers[i](state[i],action)
}
return temp;
}
}