The Developers Guide to Redux-like State Management in Angular while Keeping it a Secret

With the help of RxJS

Daniel Dughila
BucharestJS
4 min readMay 21, 2017

--

The road to Single State Management

More and more people are talking about JavaScript state management systems like Redux, MobX or Relay. Almost every article, tutorial or talk out there has something to do with the libraries above.

Let’s say you join an ongoing Angular project and you say:

Yes, I want it, I want to get inspired by Redux!

You google around and find the @ngrx/store library which is great and you cannot wait to use it. Then you talk to the team about not managing state in controllers, introducing concepts like actions, reducers, selectors, and immutability.

Depending on your team’s momentum, the decision to adopt new technologies can take a while.

In the meantime, welcome RxJS!

You already have RxJS reactive extensions bundled up in your Angular application. Embracing their power will allow you to use the principles of Redux without having the need to introduce specific terminologies like actions and reducers.

Redux can be described in three fundamental principles:

Single source of truth

State is read-only

Changes are made with pure functions

To illustrate all of this, let's build a small app which retrieves, lists and counts my Github repos, sticking to the Redux principles while using RxJS.

The state of our application will be stored in an object tree within a single store.

Modeling our data

Our application's state has a repos entity which can be in an isLoading state and can have many objects of type Repo loaded from Github.
Sometimes errors happen which means that our repos entity needs a hasError property.

There is no need for a count property because we can derive its value from the length of the repos array.

Creating a store service

Having finished modeling our data, let’s create a store service which will hold the applications’ state in a RxJS BehaviorSubject.

The store service exposes an observe method which, together with the distinctUntilChanged operator returns an observable sequence that contains only distinct contiguous elements empowering the immutable character of our state.

The second method is called dispatch and is in charge of updating our state by calling next. The method expects an event of StoreEvent. It passes the current state to that event and gets back a fresh new one.

The store service will be a provider of the store module, being injectable app-wide.

Creating events

Now that the store is complete, we need events to update it. Each event has a payload and a getNewState method which holds the reducer logic.

The StoreEvent abstract class ensures that our future events will have consistency and is, in fact, a nice way of implementing the concepts of actions and reducers without anybody noticing it.

Thinking about the process of getting repos from Github, our application will handle three events: GetRepos, GetReposSuccess, GetReposError.

Getting repos

The event has no payload, it just needs to set the state's isLoading property to true and return a new copy of it without mutations.

Repos have been fetched successfully

This event receives the repos as a payload and it stores them in our state together with setting the isLoading and hasError properties to false.

Could not retrieve repos

I know Github always works, but, let's build the error event nonetheless.

Creating the repos service

At this point, we have set up our infrastructure, having our single source of truth neatly stored away into a BehavoirSubject and our events ready to be emitted!

In order to interact with Github and fetch our data, we need a service.
Because our state is decoupled from our components, we can delegate event dispatching to this very service, making it communicate with our store.

Consuming the state

Now that we have created the service, let's consume our state and hook everything up at the component level.

We will inject our store and subscribe to the repos properties.

The async pipe is really handy, making it possible to use the subscription directly at the template level.

The interesting part consists in using RxJs operators to query our store, just like a front end database.

Notice how we derive the total count of the repos without having this information directly in our datastore.

With this said, I hope this article was useful and I can hardly wait to see your comments!

You can clone the repo from Github or visit the demo page.

Special thanks to Sabin for inspiration, one of the best engineers i know!

--

--