If you keep it like this, you just moved the problem from the connected component to the selector function: it still knows too much about the state shape.
Reducer-scoped selector functionsSelector functions defined at the root reducer level should only know about the place in the state where each combined reducer is placed.
This is true for each level in your state tree.
At each level, you extract data from that level and forward it to the next one, using “reducer-scoped” selector functions:This way, if you change where the todos reducer is “combined”, you just have to change the selector function exported from store.
js:And if you change the way your todos reducer stores the information, you just have to update the selector functions exported from todos.
js:Reducing boilerplateWith this approach, the code defining the selector at the root level is mostly boilerplate.
You get the right slice of state and handle it to the next-level reducer:If you want to rename todos to todosList as before, you have to change it in every selector.
It’s not a big deal, as the selectors are collocated with the root reducer, but we can do better.
Using a utility function you can define every selector for the same reducer at once.
The module where the reducer is defined exports a bindSelectors function.
bindSelectors receives a function (slicer in the example code) that knows how to get this reducer’s branch from the global state.
Finally, bindSelectors returns a bunch of selectors that use the slicer function.
The root reducer module uses bindSelectors to bind all the selectors defined for the todos reducer, providing the slicer function.
Finally, the component uses the exported selectors from the root reducer module.
Summing upWhile almost every article about Redux talks about selector functions as a way to decouple components from the state shape, I’ve seen very little written about decoupling the selector functions themselves (this post by Randy Coulman and the one he references by Jack Hsu are the only stuff I found about the subject).
Having worked in projects with more than 100 selectors from 30 different reducers, I’ve come to appreciate this kind of stuff.
I hope the approach described in this story will help you build more scalable Redux applications.