In this Redux: Colocating Selectors with Reducers Egghead tutorial, Dan Abramov suggests using selectors that accept the full state tree, rather than slices of state, to encapsulate knowledge of the state away from components. He argues this makes it easier to change the state structure as components have no knowledge of it, which I completely agree with.
However, the approach he suggests is that for each selector corresponding to a particular slice of state, we define it again alongside the root reducer so it can accept the full state. Surely this implementation overhead undermines what he is trying to achieve... simplifying the process of changing the state structure in the future.
In a large application with many reducers, each with many selectors, won't we inevitably run into naming collisions if we're defining all our selectors in the root reducer file? What's wrong with importing a selector directly from its related reducer and passing in global state instead of the corresponding slice of state? e.g.
const todos = (state = [], action) => {
switch (action.type) {
case 'ADD_TODO':
return [...state, todo(undefined, action)];
case 'TOGGLE_TODO':
return state.map(t => todo(t, action));
default:
return state;
}
};
export default todos;
export const getVisibleTodos = (globalState, filter) => {
switch (filter) {
case 'all':
return globalState.todos;
case 'completed':
return globalState.todos.filter(t => t.completed);
case 'active':
return globalState.todos.filter(t => !t.completed);
default:
throw new Error(`Unknown filter: ${filter}.`);
}
};
Is there any disadvantage to doing it this way?