What you should know about @ngrx selectors

Nasreddine Skandrani
Front-End Tricks — TheBlog
3 min readJun 14, 2018

--

Image associée

So i am writing this article to be able before all to save time answering the same thing in the Gitter channel of @ngrx and reference the article in futur to let new users of the lib know more quickly this little tip about selectors.

First you can check the official documentation about selectors here.

So to make the story short the selectors in your basic use of the library allow you to access a piece of state from store in your smart components.

What is behind ngrx selectors?

Basically the ngrx selector is:

pipe(map(yourSelectorMethod), distincUntilChanged())

distincUntilChanged operator from rxjs uses a ===.
So if you select in your component a value of type string, number or boolean, it’ll not trigger the selector in the component when the value doesn’t change.
But if you select an array or object, it’ll trigger always at store update because the rxjs map will create a new reference then the distincUntilChangedwill see a new reference in the selector.

Example about one problematic use case with ngrx selectors

When you use ngrx/entity/selectors => Official documentation here.

In the documetation from the link on top, let say i want to update the dom when the current user changes. You have multiple options:

Option0: [NEW ng-conf may 2019 Add On]
Custom selector option

please watch this video, i pinned the right moment: https://youtu.be/RXuSDiLmcN0?t=622

Option1: (the way you should probably not do it)
You can use directly in the component the selector selectCurrentUser.
This selector select a none primitive type.
What did we say in the section before!! object are not protected in the selector. Which means for example if you update the current list of users (entities) in the store then the selector selectCurrentUserwill trigger even if the current user never changes => it’s the same.

Option2: (the way you should probably do it)
You can use instead selectCurrentUserId. With this selector you are selecting a state of type string or number. Perfectoo!! no more issue in the component if we alter the current list of users (entities) in the store.
But you ll ask! i need the whole object user not only his id in the component. How to do this?
Your component select with this strategy:


this.store.pipe(
select(selectCurrentUserId),
withLatestFrom(selectCurrentUser)
).subscribe(([currentUserId, currentUser]) => {
// you can avoid this subscribe by using async pipe

});

This will only update if the current user ID really changes.

note:
withLatestFrom approach shown on top may not be the best way to select. Please follow discussion here to find out about another way to select.

Option3:
Wait a sec! some of you will say:

Ok! but what about if i want to watch when the current user changes but also watch for changes inside the current User attributes, If something else than the id changes like his name or email. The Option2 will not work anymore to update the component with the new state.

In this case, what you can do! hummmmm!
You can use the selector selectCurrentUser and add another
distinctUntilChanged(param1, param2) operator (example here)but this time passing some parameters to it to be able to compare the previous value vs the new with a deep equality check.
OR
You can create a selector selectCurrentUserHash that hash the current User => you’ll endup selecting a string then your selector is protected from list update as in Option2. And as in Option2 you can use the withLatestFrom in the component to access the current user object.
OR
You can create selectors for the attributes that changes inside the current user and use them directly.

Conclusion

Voila voila! this example is a really simple use case.
you can extend the content of this article for different use cases in your app (including none ngrx/entity selectors).
You are the artist :) so think twice about the selectors you are using in your components to avoid especially having junior devs after you messing up the App.

Keep up with our content by following us @FrontEndTricks & don’t forget to give it some 👏👏👏.

~ Thank you ~

--

--