I'm writing reducers for my application using ngrx/store.
Here is the layout of my application state:
{
project: {
name: string
tasks: Array<Task>
}
}
with:
interface Task {
name: string
}
I'm trying to write clean reducers in separate files.
Here is the solution i'm currently using:
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;
};
}
Store is provided using:
StoreModule.provideStore( combineReducers([{
project: projectReducer
}]) );
If i want to add other fields to my project, like a tags field:
{
project: {
name: string,
tasks: Array<Task>,
tags: Array<Tags>
}
}
I can create a separate tags.reducer.ts and use the same approach to create the corresponding reducer.
So what's wrong with this approach ?
I'm pretty sure i'm running into troubles concerning the immutability of my application state.
Exemple:
- I dispatch the CREATE_PROJECT action, i get a new state and everything is OK.
- Then i dispatch a ADD_TASK action.
- The tasksReducer itself return a brand new array of tasks, BUT the main application state is mutated ... And that is not good !
In your opinions, what's the best approach to solve this problem ?
More generally:
As my project object will grow bigger and bigger with more fields, how could i do to:
- Keep reducer separated
- Make reducer operate on isolated sub part of the 'main' reducer
- Keep my state immutable
I would be glad to share though and opinions about that !