NgRx provides reactive state management utilizing RxJs and a global state object.  In this guide, I'll explain how to implement the State, Actions, Reducer, Selectors, Effects, and how to use in a components.

Goals - Understanding the Following

  1. Why NgRx and Redux
  2. State Object
  3. Actions
  4. Reducer
  5. Selectors
  6. Effects
  7. Using in Components

Why NgRx and Redux

Angular architecture depends heavily on the observer pattern with heavy usage of RxJs.  This pattern reveals itself useful when consuming the HttpClient and EventEmitters in components, passing data to REST endpoints and through components.

Sharing data between components presents difficulties when objects mutate.  Object references change or differ between the components after mutation.  This lead to the infamous Facebook Notifications count bug.  Using the Redux pattern presents a unidirectional flow of data, and with its source of truth in a global state object, one immutable object reference is sliced and pushes through to the different observers.

Using this pattern also can help prevent numerous round requests to REST services, cutting network chatter.

For a more advanced view of how to architect a system using NgRx refer to Architecting Angular Applications with NgRx.

For a visual of this flow, reference the graphic below.

State Object

The state object is a global JavaScript object encompassing any properties required for the application.  As users interact with the application, the global state object changes, in an immutable fashion through the Reducer, and pushes changes down through to a component's observables and subscriptions.

A simple implementation of a state object exists below.

The podcastId can be consumed through selectors and pushed down to the different consuming components.  In my case for this state object, I use it as filter as the selected podcast in the user interface.

A more complex example using the EntityAdapter, a class within the @ngrx/entity package, exists below.

The EntityAdapter adds the following properties:

  1. ids - an array of ids from the entities defined per the selectId
  2. entities - defines a dictionary of the entities through the id defined in the selectId, {[selectId: string]: entity }

Actions

Actions are events that happen as a result of user interaction with the application.  Using our podcastId state example above, a user could select a specific podcast and the application would filter based on this specific podcast.

The Action class always includes a type property representing the action being dispatched.

The class SelectPodcastAction includes a type property of [alsoa.ui.podcast.component] SELECT_PODCAST', along with payload property of type string.  The payload represents the action data associated with the action necessary to complete the action.

Free Your Developers

Nx Monorepo Starter alleviates developers from re-inventing deployments on popular Google Cloud Services, standardizes on libraries, and saves time for scaffolding projects.

View on Gumroad

Reducer

The reducer generates a new state based on the action dispatched and any payload information contained within the action.  These files contain a switch statement for any action that changes and returns the new state.  Get familiar with the spread syntax as a mechanism to preserve immutability.

Selectors

Selectors provide a method to read slices of the state.

Combining selectors to retrieve slices of state and filtering through necessary data can also be achieved.  In the selector below, the selected podcastId filters through a dictionary of  podcasts to retrieve a specific podcast.

In the selector above, the selectors selectFeatureState and PodcastSelectors.selectEntities combine.  In the selectedPodcast selector, we retrieve the selectedPodcastId and a dictionary of entities from the PodcastSelectors.selectEntities in the end providing the selected podcast via entities[selectedPodcastId].

Effects

Effects exist to change or retrieve the state of an external system.  For most of my use cases, effects communicate with a REST endpoint to query, insert, update, and delete different entities.  Effects begin listening immediately for one or multiple actions.

In the case of real time communications, effects can open a stream from a service and dispatch events to modify the entity states accordingly.

In the effect above, a Firebase query opens a socket and events push through updating the state as it requires a little bit of configuration per the actions and reducer, but Firebase eliminates the difficulties of the broadcasting the type of mutation on the entity.

Component Usage

As the state changes, components can afford using OnPush change detection giving a performance boost.

In order to read data into our component, inject the Store service into the component.  Create an observable property to read a slice of data from a selector.  I prefer not to explicitly subscribe to the observable.  There exist better methods handling the subscriptions.  My preferred method uses the async pipe in the template alleviating the responsibility to explicitly unsubscribe in the component.

Summary

You should now have a better understanding of the Redux pattern, its implementation within NgRx, and how to implement it within your components.

With your understanding of NgRx and Redux, you'll need a strategy and pattern on implementing this in your application.  Next, I explain how to Architect an NgRx application.