This speaks strongly to our experience with Redux and React-Redux.
When we started out with React-Redux we found we were writing tremendous amounts of code that wired one store property to one UI element and one function which dispatched one action to a reducer that updated that value in the store. This was about 95% of our use case. The rest was coordination (reset X to default when Y changes) and async fetches.
We wrote a ‘redux-util’ to abstract away the 95%. Against Dan Abramov’s best advice, we present our utility with the shape of the entire state tree at load time, and our utility generates all of the trivial setter reducers, creates functions that dispatch actions that engage those reducers, and wires them into our components using a custom ‘connect’ which inspects PropTypes and using some property naming conventions to generate mapStateToProps and mapDispatchToProps automatically. When it works well, it’s beautify and simple.
Where it falls apart is the 5%. Junior devs, who’ve been insulated from how Redux really works don’t have the foggiest idea of how to proceed. Senior devs might be tempted to create every more intricate abstractions, and we have. But there’s definitely a point of diminishing returns where you wonder ‘why the hell don’t I just use a normal reducer and the stock ‘connect’ with mapStateToProps and mapDispatchToProps?’
I feel like there exists a clever middle ground which scales effortlessly from the simple to the complex. Our utility layer is not that, but neither is bare Redux and React-Redux.