See! Query. Read. Store.
About read and write models in NgRx, redux, flux, and friends.
Today, I’d like to blog about reading state in a store-like architecture and introduce the selectors API of NgRx. Each and every top-trending state management libraries in frontend development shares the concept of a reducer function. The idea is that “changes are made with pure functions” and — guess what— reducers are those kind of functions.
But what about reading state? With all the fancy terms like reducer, action, dispatcher, store, and more-more-more, not much attention is paid on how to read state. In this blog post, let’s take a look at both sides: writing to the store, and reading from the store.
When you look at the nice architectural diagrams — and it doesn’t matter if you’re looking at flux or NgRx or whatsoever — you’ll notice there two arrows touching the store. One pointing towards the store, one pointing away from the store.
The arrow pointing towards store represents a reducer. The dude that changes and updates the state. Let’s look at the most minimalistic example:
Do you notice that the reducer is the piece of code that touches the state object? It’s by design the only building block in the application that makes changes to the state. There we have it: the write model of the application.
On the other side, the arrow pointing away from the store represents the dude that reads the state. Although flux and redux don’t give a specific name to that building block, that arrow represents the read model of the application.
By design that’s an implementation of the CQRS pattern “segregating the operations that read data (queries) from the operations that update data (commands)”. In fact, watching Todd Motto’s course on NGRX Store and Effects made me realize that!
While flux and redux do not emphasize on the read model side, NgRx gives it a name and calls out selectors who are “methods used for obtaining slices of store state”.
Let’s also construct a minimalistic example, saying that we’d like to display the number of Todos in a counter. Here’s the code complementing our above reducer:
Selectors also allow to apply a concept called memoization, meaning that the read model only needs to update when the state changes. As long as the state isn’t mutated, the selector returns the value it computed before. In effect, think of it like a local caching strategy. Cached values are valid until the state, which is the input of the selector function, is mutated. An example:
We have a collection of Todo entries in our store and we’re displaying the number of Todos. As long as we keep the same collection in store, the count doesn’t change. Whether we display it in one, two, or many counters, it’s still the same count. Only when we update the collection, we need to re-calculate whether the count changed. Did we remove or add a Todo entity? If yes, the count changes. If we only updated an existing entry, the count stays the same but we need to re-calculcate. The good thing is that we only need to re-calculate once even if we’re displaying the count in several places.
Interestingly, NGXS also features an explicit select concept. Let me make that clear: the redux/flux architecture has a read model by design. However, some of the early implementations don’t have an explicit name for it and they don’t have an explicit API for the read model. Their read model is implicit. Libraries like NgRx and NGXS go one step further and make selectors an explicit part of the API.
In the next blog post, I’d like to look into more advanced examples and explore more in-depth features of the NgRx selector API!
Up until then, a piece of humour, contributed by my room-mate and co-worker.