That said I believe Redux is not so much about representing the state tree as it is about making its mutations centralized and predictable (the same actions, replayed, will always produce the same state). While a componentized tree often helps ensure this, it is less of a case when the state shape itself doesn’t neatly match the rendered component tree. This is the use case where Redux, in my opinion, offers some options.
If you're doing webcomponents right (i.e. adhering to the Law of Demeter, not handing out references to internal shadow/shady-DOM nodes, defining an API for possible child components), then you naturally get centralized & predictable mutations as well. The methods & child nodes of a top-level component become the API by which events can mutate the page, and then any state changes propagate down to the leaves of the component tree only via well-defined APIs.
I found that once you have web components, there's nothing stopping you from representing your entire webapp's UI in terms of semantic elements only. For example, a HN comment thread could look something like this:
All of the details about how to present a <hn-thread> or <hn-comment> are encapsulated in the definition of the custom element, and you only specify the data that changes between each one. Similarly, you could define methods on <hn-comment> that pop up a comment box when you hit "reply", for example, and this also drops out of the light DOM tree.When you do it this way, your DOM becomes basically isomorphic to what you would write in your Redux state or send in a JSON response. You could, in fact, write a trivial helper to convert between JSON and DOM, but there isn't really a need when you could just send HTML down the wire.