There's actually prior art for what you're doing (per the articles at [0] and [1]). The code will work, and the changes should show up in the Redux DevTools. Dan even described that as a possibility in some of the earlier Redux issues ([2], [3]).
Now, having said all that: I _personally_ would say that a "single SET_STATE action" approach goes against the intended spirit of Redux. One of the core principles behind Redux is that it should make it very easy for you to understand when, why, and how your state was updated, and what part of the application triggered that state update. If you only have a single SET_STATE action type, then reading the action history log in the DevTools won't tell you much useful. You can see the action contents and the diffs, but the action log itself won't have any semantic meaning, and you can't easily trace back to where the action was dispatched because the entire codebase is dispatching the same action type.
Redux also doesn't care if you do "setter-style" action naming like SET_USER_NAME and SET_USER_ADDRESS, or "event sourcing"-type naming like "USER_ATTRIBUTES_UPDATED". However, either of those approaches is going to at least provide _some_ semantic meaning, making the action log easier to read and the origin of the action easier to trace.
I'd encourage you to read through the "Structuring Reducers" section in the Redux docs [4]. In particular, the "Normalizing State Shape" page [5] talks about why we recommend normalizing your data into a flatter structure, rather than keeping it nested.
Finally, you might want to read through my two-part blog post "The Tao of Redux" [6], which goes into detail on the history and design of Redux, the intent for how it _should_ be used, and why common usage patterns exist.
[0] https://medium.com/@jeswin/implementing-redux-is-tedious-but...
[1] https://medium.com/@benevolentNinja/minimal-redux-setup-e6a1...
[2] https://github.com/reactjs/redux/issues/155#issuecomment-113...
[3] https://github.com/reactjs/redux/pull/140#issuecomment-11395...
[4] http://redux.js.org/docs/recipes/StructuringReducers.html
[5] http://redux.js.org/docs/recipes/reducers/NormalizingStateSh...
[6] http://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao... , http://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao...
> when, why, and how your state was updated, and what part of the application triggered that state update.
Well, when I said "single" action I was fudging a bit; I have a switch statement with a dozen action types that all are equivalent to the PLAIN_MERGE action. The point is more that I don't have much code inside my actions and reducers, except for the stuff that needs to see the "whole program state" - everything else tends to be encapsulated inside the components.
Also, I think you overstate the lack of semantic meaning: that state tree I pass along, together with the occasional custom action type tag, tells me exactly where the dispatch originates from. Of all the problems I have when debugging my app, finding the source of the dispatch is never one of them.
I ended up making a dead-simple merge(oldObj, newObj) function that's halfway between Object.assign({}, ..) and lodash.merge() (it doesn't merge arrays)[0]. It makes it easy for me to update deeply nested state trees, provided the nested data is simple enough.
As a result, 99% of my dispatches uses one action type, PLAIN_MERGE, and a dumb state tree indicating what I'm updating, like so:
That might be some deep nesting, but it actually reflects the structure of the interface too, so it's kinda self-documenting.The associated reducer is simply return merge(state, action.state). Again, maybe I'm missing something but it seems like a pretty simple and effective solution to me?
[0] https://gist.github.com/JobLeonard/c4292594ce4d439ab20ec109f...