There are two ways of thinking of about UI: in terms of state or in terms of interactions.
This pattern is common in the Redux community. In this style of thinking, the building blocks of the app are reducers. Each reducer is tightly coupled to a specific part of the state. It decides how to respond to actions from the outside. It has full control over its part of the state, and that’s its only concern.
The main take away here is that state is a smart essence.
In this model, application state is represented as an inert tree.
branches
and leaves
. A branch doesn’t hold any state itself but is a grouping of leaves that each hold chunks of the application state. For example, the branch state.entities
groups the states of the posts
leaf, comments
leaf, etc. When a user interacts with the UI, the application changes its state in response. As opposed to a reducers-based model, state is a passive data container here. And interactions are the ones in charge.
Let’s say a user manages his posts and removes one of them by clicking the “Delete” button. What’s happening under the hood? The state of this UI part is stored in the state.ui.postsList
leaf. Clicking on the button, a user triggers an action creator and the app starts a request to the server. In response to this action, postId
is added to the processingPosts
set to show the spinner in the UI. It requires a change of the single ui.postsList
leaf. Let’s describe it in the interaction module:
When a server responds with a success:
postId
must be removed from the processingPosts
entities.posts
leafThis action entails changing 2 different leaves:
Notice how easy it is to follow what’s going on here because the logic of a single interaction is contained entirely in a single module. Try it and you will see how easy it is writing code like this.
The key point is that an interaction decides which part(s) of the state will be updated in response to the action.
Under the hood, redux-tree
is an alternative version of Redux’s combineReducers
, which makes it possible to represent changes to the state as a sequence of functions. This allows describing interactions in a very concise and consistent manner.
It’s super easy to integrate redux-tree
into existing codebases as it supports classic reducers (so incremental adoption is absolutely possible) and it should be compatible with the most of the packages from Redux ecosystem. The main change it introduces is how Redux internally iterates over the reducers.
In the initial release of redux-tree
, state is represented as an Immutable Record. We use Immutable a lot in our apps: it makes it easier to handle deep updates and prevent state mutations, Record allows access to properties using dot notation (as opposed to getters), and it’s possible to strongly type the state tree with Flow. So, immutable-js
is required (at least for now).
Check out:
And let me know how it works for you!