NgRx – Strongly Typing the State and Building Selectors

Introduction

In an introductory post we started with the basics of NgRx.

We covered the first steps towards centralized state management for our application using NgRx which is Redux pattern tailored for Angular.

We installed the NgRx store and wired-it up in our application. We saw, how we can structure our application state in small slices for easy maintenance using Feature Module State Composition.

Today we’ll take next step and strongly type our application state. We’ll also see how to build and use selectors to select any bit of state information from our state slices.

Strongly Typing the State

Following is the code from previous post:

Notice that we are using any for the generic store type. We can improve this by using typescript interfaces to strongly typing our state.

Basically, we can have multiple interfaces defined for each slice of state and then we can define one interface which composes all these states.

But first lets just focus on products slice of state. First question, where to define these interfaces for state?

Defining state interfaces in Reducer

In previous post, we said that our Reducers provide a representation of our application state, so it makes sense to define our feature state interfaces in their associated reducers.

here we’ve defined interface for the product slice of state.

We can follow this for other features of our application to define corresponding interfaces.

Defining Application State Interface

Similar to feature state, we can define an interface for our angular application as follows

Now we have a complete structure of state, in-place. It currently has two feature slices. As we build other features, we’ll add them here.

However, there is an issue with this approach. We’ve just broken the lazy loading boundary by directly importing ProductState into application state. You can check this post for information about lazy loading of angular modules.

So what can we do?

We’ll keep just the state which isn’t lazy loaded into the app state interface as shown below:

then in products feature code, we’ll extend that definition of our global application state to include the product slice of state as shown below:

Since this code is part of product feature, we keep it within our lazy loading bourderies.

Now, we have a single state interface, which represents our entire state tree.

Lets use these interfaces to strongly type our state as follows:

now for the component, we can strongly type the store as follows:

Note: We are importing extended state from reducer, so our component will have access to entire application state.

With this, our state is strongly typed; we’ll have static type checking benefits and code intellisense from the editor; so less bugs.

All it took to strongly type our state was to define a set of interfaces that laid out the structure of that state. We then used these interfaces as a type whenever we reference the global application state or any particular slice of state.

Setting the Initial State Values

Strongly typing and setting initial sate, brings benefits of strong typing and make our code more predictable. We can strongly type initial state and initialize it as follows

if we test our application and check the debugger, we can see that initial state is set as we defined in our code

Next, lets discuss selectors more in details.

Building a Selector

Following is the store subscription code, we have in our component:

Currently it suffers from following issues

  1. We have a stringly selector in our component waiting for typos.
  2. We explicitly retrieve a property (products.showProductCode) from the store, making assumption about the store structure. (meaning if we ever change store structure; e.g. reorganizing it into sub-slices; we have to find every select and update its code.)
  3. Lastly, this code watches for any changes to any property in the products slice of state, so this code is notified even if the showProductCode property was not changed.

How do we make this better?

Answer: Selectors

A selector is a reusable query of our store (like a stored procedure for accessing our in-memory state information).

Selectors allow us to keep one copy of the state in store, but project it into different shapes, making it easier to access by our components and services.

Our component use selectors to select state from our store; adding a level of abstraction between our store structure and our component.

Benefits of using selectors

  • Provide a strongly typed API.
  • Decouples the store from the components.
  • Can encapsulate complex data transformations.
  • They are reusable.
  • They are memoized (cached).

A selector is a function that drills into the store and returns a specific bit of state.

Two basic types of functions provided by NgRx library are

  • CreateFeatureSelector: This function allows us to get feature slice of state. (we typically do not export this)
  • CreateSelector: This function allows us to get any bit of state by composing selectors to navigate down the state tree. We can use it select a very specific bit of state. (this is exported)

A selector should be a pure function.

We can define our selector at the same place where our reducer is defined to keep things close; but you can put them where you see those fit in your application. (We’ll see a common place for this later).

Following is how we defined feature selector getProductFeatureState which is not exported; thus internal to this class. We then defined and exported the general selector getProductCode which uses a projector function.

In similar way, we can define other selectors for product as follows

Now, we have selectors, lets see how to use those next.

Using selectors

We’ll update our component code use the selector as follows

This simplifies things and also decouples our component from the store structure which can change as needed without requiring change here in component.

We can now test the application to see that it works as before without any issues.

Composing Selectors

We already saw how to compose selectors when we build the getShowProductCode selector in previous section. However, we can combine selectors further. Lets see an example below

This selector uses array’s find method for selecting current product based on product id.

We’ll finish this post at this point and will continue our learning in next article.

The source code of this application is available on this git repository and online deployed application can be accessed from this URL.

Check Lists

Check List – Strongly Typing State

  • Define an interface for each slice of state.
  • Compose those interfaces to define the global application state.
  • Use these interfaces to strongly type the state throughout the application.
  • To aid predictability, provide initial state for each slice.

Check List – Selectors

  • Build selectors to define reusable state queries.
  • Define a feature selector for feature slice of the sate.
  • Use a general selector to return any bit of state from store using selectors composition.

Summary

In this post we strongly typed our state using typescript interfaces which benefits from static type checking and code intellisense. We can compose these interfaces to define the whole application state.

We covered how to build and use selectors which provides a nice abstraction between our store structure and component and how we can compose selectors to have fine grained control on every bit of state information.

Let me know if you have any comments or questions. Till next time, happy coding.

1 thought on “NgRx – Strongly Typing the State and Building Selectors”

Comments are closed.