NgRx Selectors – How to Stop Worrying about your Store Structure

Store

It is one of the biggest things. It can be subscribed from, one can get state changes when they are updated.

How to structure the store for an entire app?

There might be a component which renders a list of current orders.

The obvious step can be to take the list of current orders and make it a custom slice in the store. There is another component which is responsible for rendering past orders. Take that component state and store it in the store as well.

0.png

But then the requirement is to store all orders. All orders are stored as a third slice in the store.

In the beginning, the reducer was actually sort of easy, which was a trick, for the developer to follow the pattern. Switch on the order load success. The array was taken and started to be filtered again. So the current order can be received by just filtering on the ‘is Active’ property.

1.png

In order to get past orders, it would be inverted.

This was supposedly easy until the update part came on.

For updating things, they can be created or deleted or both.

For an update something like this could be done:

There are too many loops here, all orders, past order- it needs to be manually integrated. Detect the part which requires change and rewinds it to the state change.

This is just about one reducer, if there were 100 reducers or more than that, it was going to spiral out control.

Skimming through the code base and analyzing reducer, it is important to comprehend what is happening.

It felt like something was missing, what was it?

Back to the drawing board, this diagram was drawn

3.png

Dispatch something, put it in a store and get a state back- this was the expectation.

The problem with the diagram above is that, if these three tools are used, ACTION, REDUCER and STATE, the developer will face the problems.

Redo the diagram.

4.png

The addition of selectors is an important change, using selectors a lot of problems can be dealt with.

Selectors are queries to your store

Selectors are a fundamental concept of NgRx. There are not just 3 circles, there are 4. Selectors are really easy to learn because they are just queries to the store.

Selector benefits

Selectors provide a lot of great benefits like:

Ø  It provides a nice API for composing view modules.

Ø  It can reduce action boilerplate.

Ø  It can help in simplifying the reducers and it allows memoization.

Ø  It has the routing state as well.

Ø  Refactor the reducer for selectors

Ø  It is easy to refactor the store for selectors.

Before the three slicing of state and filtering it out. Deleting the items in order to reduce the track load. Now, instead of keeping track of 3 pieces of state, it is required to keep track of just 1.

Like before, when it was required to update state, it is better to do an order added action which is really simple. All that is to be done is the addition of a new order, where one piece of state is updated not 3 pieces of state.

5.png

The process has kind of reflected the producer- the three slices of state has been taken out and now they can be treated as more of a view model.

createFeatureSelector()

This is the part where create feature selector is introduced and it is a sibling to createSelector().

createSelector()

These are the two things which are required to be created, where one can go and compose those view models. These posts come from NgRx store package which can be imported.

To create a new reference to this new slice of a single slice of the state which is present. A feature selector is taken, which is going to pass in a string value.

The difference between the two is that to create feature selector, there are feature modules in angular, there is an app module. There is lazy loaded orders module. The feature selector is for feature modules, it would dynamically bind itself to the state tree.

This is how a reference to it can be created.

6.png

It is required to get the current orders, this is how it is going to be composed.

The first selector can be passed in as the first argument. A function argument is received, orders are given back. So this function will get executed and then the things can get mapped over, filtered and the active items can be returned.

This function is going to project a function.

There are also, the past orders. The expression can be inverted in the reducer.

7.png

Using the selector is really easy. Inject the inject stores into the component. Use the select method and pass in the selector, as it is usually used with the Select API.

Before there were 3 view models in the store which are now switched to having 3 selectors. A very big benefit of these 3 selectors is that they are reactive.

Reactive

For example, there is a current order component which is going to dispatch that a new current item was added. It will re-compute the selectors for any query it matches.

Considering it is a new item, it will re-compute the selector for getting current orders as well as getting all orders.

8.png

It will not update for getting past orders because it was not affected by it.

It’s just one update to synchronize multiple pieces of state rather than managing multiple actions and trying to keep everything in sync in the store.

Assume a new requirement, where an order is to be called. This will be accessed by its ID. There are multiple ways using which it can be done.

Here is how it is done using a selector.

9.png

Since an ID is involved, it is expected that something can be passed into it and get something back.

These selectors can be reused, they can be composed in multiple places. So, all of the orders can be passed in.

Using array prototype fine method, the collection will be iterated and that single ID can be found.

This is the issue with this method.

What if it is required to render 10,000 items?  

Entity pattern

Instead of going through 1000s of items to retrieve one, it is efficient to just quickly access that one item. This is something which can be done with the entity pattern.

Starting from NgRx, this is a really nice thing to dive in to from the get-go.

There are three here, but assuming 10,000 items. This is an array.

The proposition with the entity pattern is, there are 3 IDs (1, 2 and 3)

10.png

Now, if these are flattened to an object structure. These unique IDs are taken which ideally would be generated on the server. The object 1 gives order 1.

The benefit with this is that iteration is required and there are 10,000 items, it will not be possible to do something like this.

Entity pattern in a reducer

Using the entity pattern in a reducer is actually very easy because it standardizes how I can be written.

Here the developer is getting the order back in the form of an array. The requirement for it is to be an object, not an array.

11.png

Now, that they are in the form of entities, it is easier to put them up as a property on the state tree.

The app is built, ng 4s are used and everything is changed to an entity pattern, which immediately breaks everything.

In reality, there is order and the returned value is in .entity. One reference to it can be created.

The requirement is transformed these entities back into an array for a view model. View models cannot be used in reducers, this is why they can be then composed.

Object keys which will give the previous example, where there was 1, 2 and 3. They are then iterated and each entity is returned. A new array is taken out from this.

12.png

The benefit is that it is just one data structure. Two selectors are used, the data is in one format; object forms and there is also an array form.

Entity pattern= fast object lookups

If the requirement is to access something which is in a list of 10,000 items, the pattern will help in getting to it just as fast as the first item.

It simplifies the reducers.

13.png

Entity pattern= awesome routing

With the getOrderById selector, an ID is required to get an order, so it makes sense that if a router path was taken, of /order/1. This 1 is the obvious candidate to pass into this ID.

There is this order detail component.

Go to the router and get the router state. This order ID is the router state /orders/1. This ID can be selected and put into the selector.

14.png

Remove router code form the component

Routing is not required in the component. It belongs sin route guards like resolvers.

The routing code can be used with selectors.

The benefit of doing this is, the routing is removed from the component, but the whole app is treated.

There are root reducer and state property. This state property can be populated with anything which is available on the activated route snapshot.

15.png

Create a new feature selector which will probably be an in-app module. Create a feature selector which reference this route to the reducer.

The entities and the route state in the projector function are given in the order in which they were passed in.

16.png

That single entity can be looked up without loops and it is fast and the order Id is accessed as well which available on that params. In the background, the router store package keeps all of them in sync.

17.png

Using this in the component, refactor can be accessed and order ID is not required anymore. The selectors are not called as functions. No routing code in the component.

The new recipe for your store

18.png