我正在使用ngrx / store为我的应用程序编写reducer。
以下是我的应用程序状态的布局:
{
project: {
name: string
tasks: Array<Task>
}
}
with:
interface Task {
name: string
}
我正在尝试在单独的文件中编写干净的reducer。
project.reducer.ts
import {tasksReducer} from './tasks.reducer';
const projectReducer = (state:Project = null, action: Action): Project => {
switch (action.type) {
case 'CREATE_PROJECT':
return {
name :'New project',
tasks: []
};
};
state.tasks = tasksReducer( state.tasks, action );
return state;
}
tasks.reducer.ts
export const tasksReducer = (state:Array<Task> = [], action: Action): Array<Task> => {
switch (action.type) {
case 'ADD_TASK':
return [...state, { name: 'New task' ];
default:
return state;
};
}
使用以下商品提供商店:
StoreModule.provideStore( combineReducers([{
project: projectReducer
}]) );
{
project: {
name: string,
tasks: Array<Task>,
tags: Array<Tags>
}
}
我可以创建一个单独的 tags.reducer.ts ,并使用相同的方法创建相应的reducer。
我很确定我遇到了有关应用程序状态不可变性的麻烦。
例:
在您的意见中,解决此问题的最佳方法是什么?
随着我的项目对象越来越大,越来越多的领域,我该怎么做:
我很乐意与大家分享这些意见!
答案 0 :(得分:2)
首先围绕你的projectReducer做一些评论。 您在switch语句中缺少默认大小写,这非常重要。 (见http://blog.kwintenp.com/how-to-write-clean-reducers-and-test-them/#defaultcase)。所以将它添加到该reducer:
default:
return state;
其次,在调用taskReducer时,你正在做一些奇怪的事情。调用projectReducer时,您正在执行的操作始终调用taskReducer。实际上,当你想要调用taskReducer时,只要它是一个动作,他就可以做一些事情:
case 'ADD_TASK':
// call it here
您也在覆盖当前状态的任务属性。正如你所说,你正在改变你的状态,这是一个明确的事情要避免。您可以利用Object.assign运算符来完成您想要的操作(整个修复):
const projectReducer = (state:Project = null, action: Action): Project => {
switch (action.type) {
case 'CREATE_PROJECT':
return {
name :'New project',
tasks: []
};
case 'ADD_TASK':
return Object.assign({}, state, {tasks: tasksReducer( state.tasks, action )};
default:
return state;
};
}
现在,当您将任务更改为任务时,您正在创建一个新的Project对象,这就是您想要的。
我建议你阅读我的整篇博文,了解如何以干净的方式编写减速器。
你的一般性问题可能有详细的答案,但我想这会跳过这一点。下面简短的答案。
保持减速器分离
- &GT;您正在使用combineReducers辅助方法,这是让您的Reducer分离的好方法。
让减速机在“主要”的隔离子部分上运行。减速器
- &GT;与上述相同
让我的状态保持不变
- &GT;按照我的博客文章中的提示,在需要时使用Object.assign和spread运算符。