Redux with Observable Stores in Angular
Tags: angular, javascript, redux, typescript
Published: 2019-05-02 19:48:27

It's turning out that 2019 is the year of the Observable store at ng-conf with several speakers advocating for this pattern in Angular apps.

I recently hopped off a large project that used NgRx for state management in Angular and have to say I was largely overwhelmed at first. A common complaint with NgRx is that it requires a lot of boilerplate. It's true that maintaining a separation of concerns can get out of hand when implementing selectors, actions, reducers and effects in NgRx. It can be very hard for a noob to understand how NgRx implements redux, let alone handle all the files that can be produced. Even seasoned senior engineers can be humbled by the experience.

![NgRx kinda felt like this](https://media.giphy.com/media/l1KVcPKdsU0sRSSt2/giphy.gif)

Redux doesn't have to be this complicated. The purpose of Redux is to simplify state management in complex applications with a pattern for unidirectional data flow. Keeping the pattern simple has some advantages.

- Those unfamiliar with Redux can ramp up faster
- Scale faster with less boilerplate
- Not using another library will make the bundle smaller
- Control how state management behaves

## RxJS BehaviorSubject

It so happens NgRx isn't the only way you can implement a redux pattern in Angular. We already have tools at our disposal in RxJS that allow us to create a store with Observables. The pattern I'm talking about is called Observable stores. The simplest expression of an Observable store looks like this.

```typescript
this._state$ = new BehaviorSubject(initialState);
```

RxJS has `BehaviorSubject` which essentially gives us the API of an Observable, but also maintains state as well. `BehaviorSubject` takes an initial state.

## Observable Store

If we wanted to abstract the ability to create an Observable store in an application it could look like this.

```typescript

export interface AbstractState {
  [key: string]: any;
}

export class Store {

  private _state$: BehaviorSubject<AbstractState>;
  public state$: Observable<AbstractState>;

  constructor (initialState: AbstractState) {
    this._state$ = new BehaviorSubject(initialState);
    this.state$ = this._state$.asObservable() as Observable<AbstractState>;
  }

  get state(): AbstractState {
    return this._state$.getValue();
  }

  setState (nextState: AbstractState): void {
    this._state$.next(nextState);
  }

}
```

That's really all there is to abstracting an Observable store!

![](https://media.giphy.com/media/WnCAPfflyfZjG/giphy.gif) 

The Store class has a private property that is the BehaviorSubject. A property called `state$` is exposed publicly for us to use throughout the application. We can call `getState()` to retrieve state or `setState` to change state. By doing it this way we retain all the characteristics of an Observable including history, error handling, all the jazz. And it's so simple compared to NgRx.


## Implementing State

Then if we wanted to create some state in our application it could look like this.

```typescript
export interface SomeModel {
  name: string
}

export class LocalState {
  someModel: SomeModel[] = [];
}

@Injectable()
export class LocalStore extends Store {
  public state$: Observable<LocalState>;
  constructor () {
      super(new LocalState());
  }
}

```

Some notes about the above implementation. Notice we have declared a class to handle some local state, then declared `state$` for `LocalStore`. This is to ensure we are working with `LocalState` as opposed to `AbstractState`. Then in the constructor we call `super`, passing in LocalState to instantiate the `BehaviorSubject` with the proper state.

## Using State in Components

Now we have some local state it's time to interact with it in a component. Just inject `LocalStore` and you don't even need `ngOnInit` to subscribe to state changes. 

```typescript

export class MyComponent {
  constructor(public store: LocalStore) {}
}

```

In the component's template you can now use state with the `async` Pipe. The view will automatically be subscribed to a chunk of state this way and handle unsubscribing as well.

```html
<ul>
  <li *ngFor="let item of (store.state$ | async).someModel as SomeModel">{{item.name}}</li>
</ul>
```

It's really that easy to hook up an Observable store in Angular! So far we only have this idea of state, which is one part of the redux pattern. What does it look like if we wanted to implement reducers and actions? Any way we want now we have implemented our own Observable store!

Now you can get back some of that "me time" NgRx took away from you.

![](https://media.giphy.com/media/l46C5MHNo0z9vXzvW/giphy.gif)


There's more to redux than just state. What if you wanted to manage your state with the action and reducer patterns found in redux, but in this custom implementation? 

## Actions and Reducers

This is just one way to implement actions and reducers and it so happens to look similar to NgRx, but with far less boilerplate.

First let's create an enum where we define actions and create an interface for what an action looks like.

```typescript
export enum LocalActions {
  ADD = '[SomeModel] Add',
  REPLACE = '[SomeModel] Replace',
  FETCH = '[SomeModel] Fetch'
}

export interface LocalAction {
  type: string;
  payload?: SomeModel[];
}
```

Now we can add a reducer method to the LocalStore to handle different actions.

```typescript
reducer(state: LocalState, action?: LocalAction) {
  switch (action.type) {
    case LocalActions.ADD:
      return {
        ...state,
        someModel: [...state.someModel, action.payload]
      };
    case LocalActions.REPLACE:
      return {
        ...state,
        someModel: action.payload
      };
    case LocalActions.FETCH:
     this._fetch$ = this.service.fetchSomeModel().pipe(
       map(res => this.actions.emit({ type: LocalActions.REPLACE, 
                                      payload: res }))
       ).subscribe();
}
```

Notice the FETCH action calls a service method? To maintain a separation of concerns, we can keep all API requests on their own service and then inject that into the LocalState class.

```typescript
@Injectable()
export class LocalStore extends Store {
  public state$: Observable<LocalState>;
  private _fetch$: Subscription;
  constructor (public service: LocalService) {
      super(new LocalState());
  }
}
```

In order for LocalStore to automatically call the reducer on state change we need to update the Store class it extends from. Here we'll add a subscription to the store's actions, which we declare here as an EventEmitter so all classes that extend from store can now emit actions.

```typescript
@Injectable()
export class Store {

  private _subscription$: Subscription;
  private _state$: BehaviorSubject<AbstractState>;
  public state$: Observable<AbstractState>;
  public actions: EventEmitter<AbstractAction> = new EventEmitter();

  constructor (initialState: AbstractState) {
    this._state$ = new BehaviorSubject(initialState);
    this.state$ = this._state$.asObservable() as Observable<AbstractState>;
    this._subscription$ = from(this.actions).pipe(
        map((a: AbstractAction) => this.reducer(this.state, a)),
        map((s: AbstractState) => this.setState(s))
    ).subscribe();
  }
  ...
  reducer(state: AbstractState, action?: AbstractAction) {
      return state;
  }

```

Now anywhere in our application, like in the Component we declared above we can make a backend request and populate state with the `FETCH` action!

```typescript
this.store.actions.emit({ type: LocalActions.FETCH });
```

## What happened again?

Let's take the journey here to see what happens to this specific action.

In `Store` the emitter we dispatched the action has a subscription that calls the reducer.

```typescript
this._subscription$ = from(this.actions).pipe(
    map((a: AbstractAction) => this.reducer(this.state, a)),
```
In the reducer, we make an http request on a service and when successful dispatch another action with the response.

```typescript
case LocalActions.FETCH:
this.service.fetchSomeModel().pipe(
       map(res => this.actions.emit({ type: LocalActions.REPLACE, 
                                      payload: res }))
```

In the reducer, passing in the `REPLACE` action will overwrite the state.

```typescript
case LocalActions.REPLACE:
  return {
    ...state,
    someModel: action.payload
  };
```

Since the subscription to our EventEmitter on State also updates state by calling `setState()` for us, the view will automatically pick up the changes to state.

```typescript
from(this.actions).pipe(
        map((a: AbstractAction) => this.reducer(this.state, a)),
        map((s: AbstractState) => this.setState(s))
    ).subscribe();
```

This means in our component we only needed to dispatch an action to update the view. The async pipe handles the subscription to state for us.


```html
<ul>
  <li *ngFor="let item of (store.state$ | async).someModel as SomeModel">{{item.name}}</li>
</ul>
```

And there you have it! The important take away here is redux can be as simple or as complicated as you make it. By coding a mechanism for state yourself with observable stores you can understand whats going on behind the scenes with state management in rather complex libraries. Redux can be implemented in Angular with minimal boilerplate compared to NgRx and still provide a separation of concerns in our application. 


## But don't take my word for it.

Check out these blog posts and videos for more information about implementing Observable Stores.

[Simplifying Front-End State Management with Observable Store](https://blog.codewithdan.com/simplifying-front-end-state-management-with-observable-store/) by Dan Wahlin.

[State management in Angular with observable store services](https://jurebajt.com/state-management-in-angular-with-observable-store-services/) by Jure Bajt.

[View Facades + RxJS](https://blog.angularindepth.com/angular-you-may-not-need-ngrx-e80546cc56ee) by Thomas Burleson.


I was first exposed to this idea of Observable stores from Thomas Burleson's post. Years ago my team architected an entire AngularJS application based off a talk he did at ng-conf. I was so happy with the results. Years later when I read his post [View Facades + RxJS](https://blog.angularindepth.com/angular-you-may-not-need-ngrx-e80546cc56ee) I chose to give service facades and Observable stores a try. I haven't looked back since. Sorry NgRx.  

At ng-conf 2019 Observable stores are all the rage with multiple presentations about using RxJS to provide state to applications. As the YouTube videos are released I'll post links to them here.

[Data Composition With RxJS](https://youtu.be/Z76QlSpYcck) presented by Deborah Kurata.