Congratulations, you’ve managed to create the perfect NgRx store with states, actions, reducers, and even effects. Nevertheless, something is still missing. It feels like every time you want to make a use of states in your angular components, you find yourself writing (or copy/pasting) the same selects over and over again.
This (and lots of other problems you are not even aware of), can be solved by using NgRx selectors. Combine the NgRx selectors with a store facade and you will get a true power couple.
Let’s say you have a grocery store that holds the state of your groceries:
Now, imagine that you need to use your vegetablesState in a restaurant component.
In addition, we have some conditions that should be met:
To achieve the above goals, a minimal code should look like:
This will work, but imagine you’d like to use salad$ with other components. To do this, we will have to add the same chain of code into every component.
Do you understand where I’m going with this?
The computation inside the select() method is triggered after any component subscribes to the store. For instance, the action of filtering only the 🍅 and 🥬 vegetables will happen for every component, in spite of the fact that the results are the same.
This can get even worse in more complicated streams which combine store results with other observables.
Repeating yourself is always bad, and this case is not an exception. Let’s look at another component, home.component.ts. We want to prepare the same base salad at home, but this time, we want to add some 🧂 at the end of the preparation to give it some flavor.
This is how our home component would turn out:
Most of the salad preparation here is just the same as it is in the restaurant component.
Makes code look very cluttered and hard to maintain. RxJs is not making it easier on us with all the diagonal function chains, and those long selects are not helping either.
At anecdotes, we have a pretty strict approach to our unit-tests policy—every feature merged into the develop branch must include unit-tests. No doubt, it is much harder to create solid unit-tests fast for your component, when you have to write tests of the logic inside your select calls over and over again.
Store facade is a concept based on the “facade” design pattern. Its main purpose is “to hide” all the complex logic of NgRx under a readable and reusable API service. This will make things much more convenient for the developers working with your store.
To make it more visual, I took the liberty of adding store facade to the original NgRx lifecycle diagram (which can be found here).
As you can see, our component interacts only with the store facade. This, in contrast to the previous logic, in which the component interacted both with selectors (directly with store if you weren’t using selectors) and with actions. This is because the NgRx selectors were providing the data and actions were called when an action was taken by the user and needed to be updated in the store.
So how do we reach it?
Now you can consume your veggiesSalad$ from any component/service that you want, without the need of actually preparing it.
Our next step is to create asaltedSalad$, save it in the store facade and consume from everywhere we want. The best part is that we can use the veggiesSalad$ as a base salad.
Here is how it will look in the store facade:
And here is how small our ngOnInit() of the restaurant and home components became:
Thanks to our new store facade, we’ve achieved the following goals:
✅ Enhanced readability
✅ Increased testability — No example here (maybe in another blog post), but to sum it up — it’s much easier for developers to write tests. They just need to inject a “mock” store facade service into the tested component, rather than mocking the same logic for every component test.
✅ Improved performance — Thanks to saving veggiesSalad as a property on a single service and using shareReplay().
However, we still can improve all those points even more, bear with me just a little more!
“Selectors are pure functions used for obtaining slices of store state.” (ngrx official docs)
Basically they allow you to create reusable and smart select() functions. Those functions receive fragments of the store state as arguments, perform a certain logic inside, and return the result.
So what is so special about them?
They are capable of memorizing stuff! But what does that mean?
It means that the logic inside the selectors won’t be triggered unless the specific slice of state hasn’t changed. To explain it better, let’s take a closer look at the following example (we will use the example of veggiesSalad$ from before):
The following code example is a bonus. In our store facade (the real one in anecdotes.ai), we check whether certain entities are initialized. To avoid adding filter() operator to every facade property, we’ve added a generic selectEntitiesAfterInit pipeable function. It receives the selector, filters the desired values, and returns it. There you can chain any operators you want.
Now, use the last specific pipeable function in the store facade (add it like an operator to the pipe of your store).
Now we have our reusable selector in place and we can use it wherever we want.
We learned why and how to utilize the power of NgRx selectors and store facade. We also witnessed some code examples which are just a taste of the awesome things you can do with them.
Let me know if you would be interested to learn about any ofthe the following topics:
👉 Integrating NgRx store into your project — from scratch
👉 Testing NgRx store with store facade
👉 NgRx selectors with web workers