This lesson is for PRO members.

Unlock this lesson NOW!
Already subscribed? sign in

Using ngrx/store and Reducers for Angular 2 Application State

5:12 Angular 2 lesson by

ngrx/store is a library that simplifies common RxJS patterns for managing state and gives you an easy api to use it within your Angular 2 application. This lesson shows how to convert a common startWith and scan stream into an ngrx Store and reducer.

Get the Code Now
click to level up

egghead.io comment guidelines

Avatar
egghead.io

ngrx/store is a library that simplifies common RxJS patterns for managing state and gives you an easy api to use it within your Angular 2 application. This lesson shows how to convert a common startWith and scan stream into an ngrx Store and reducer.

Avatar
Oleksii Filippov

I think lesson #7 is outdated. It is not possible to create store:Store variable in the constructor. There is an compile error: Generic type 'Store requires 1 type arguments. Make store:Store instead

In reply to egghead.io
Avatar
Nathan Brenner

This works, and it matches the current docs:

import { StoreModule } from '@ngrx/store';
@NgModule({
    imports: [ StoreModule.provideStore({ clock: clock }, { clock: new Date() })

The first parameter to the provideStore method is the reducer function, the second is the initialized state.

Avatar
Doug

I'm still getting an error in ng2:

ERROR in [default] /Users/dougboyd/look/learn-rxjs/src/app/app.component.ts:21:21 
Generic type 'Store<T>' requires 1 type argument(s).
Child html-webpack-plugin for "index.html":
In reply to Nathan Brenner
Avatar
Jon

I am too. Seems to be a recurring pattern with these courses..Angular2/RxJs is changing too quickly for EggHead to keep up.

In reply to Doug
Avatar
James

It looks like you have to install ngrx separately

step 1 - install from here https://github.com/ngrx/store

npm install @ngrx/core @ngrx/store --save

step 2 - add to your module

import { clock } from './reducers'
import { StoreModule } from 'ngrx/store'

@Ngmodule({
  imports: [ // NOT bootstrap like in the demo
    StoreModule.provideStore({ clock })
 // ... the rest of your module

step 3 - add to your component

import { Store } from '@ngrx/store'

export class AppComponent {
  click$ = new Subject()
  clock
  constructor(store: Store<any>) { // either use `any` type or swap in your class interface for typescript
    this.clock = store.select('clock')
// ...

step 4 - add your .reducers.ts

export const clock = (state: Date = new Date(), {type}) => {
  const date = new Date(state.getTime());
  switch (type) {
    case 'second':
      date.setSeconds(date.getSeconds() + 1);
      return date;
    case 'hour':
      date.setHours(date.getHours() + 1);
      return date;
  }
  return state;
}

Hope this helps!

In reply to Jon

What we've done here with start with in scan is actually a very, very common pattern where you have an initial value, and then you want to change the value based on some other values that come through, and you want to keep track of it.

There is a library that can help us with this, so we don't manage all of this ourselves, and we can move all of this into a different file. We're going to come over here. I'm going to create in my source a new filed called "Reducers."

In my reducers, I'm going to set a function called "Clock." This is going to be our clock reducer. Clock takes a state. Instead of using "Start with," we'll set an initial value of "New date." Then for now I'm going to return the state.

If this function is called, it's going to set this state to new date and return the state. To use this reducer or this clock function, we need to actually bootstrap it into our application, which means I need to add something to the list of my dependencies here.

My dependencies are an array after that component, and I'm going to say, "Provide store." Where provide store is going to come from is from NGRX/Store. I'll go ahead and provide store. The store that I want to provide is an object with key value pairs to those reducers.

I want to get clock, and I need to import clock. I'll import from reducers and I'll import clock. We've hooked this up where we have this store that uses the clock reducer. This is all basically configuration stuff.

Get used to it, and don't worry too much about it other than passing the reducers into this object and then providing them to the store. Then that gives you immediate access after you import store from MGRX.

We can use angular twos, dependency injection to grab the store using a type. Our clock instead of this big stream can be store, select, and then a string of clock to grab whatever comes from that clock reducer.

I'll hit save. I'll refresh, and then you can see we have this new date and it's frozen at that time that the reducer was called and the new date was set. With this stream, I'm going to get rid of everything and start with a scan. I'm going to move this over to my reducers.

Instead of doing these if statements, I'm actually going to switch on an action type. We'll have actions come through and actions have a -- I'm going to de-structure this -- a type property on them. Type in here is what I can pass along. Instead of to start with in scan, I'm going to subscribe to this stream.

The type is what comes in, and I'm going to say, "Store.dispatch an object with that type on it." We're going to take this type of hour, this type of second, and it gets pushed into subscribe, and gets dispatched to the store, which gets handled in the reducer.

We have the type here where I can switch on the type. If the type is second, we want to do this and return date. If the type is hour, we want to do this and return the date. We'll delete all of these. We've refactored this into something that can, when I refresh...

You can see I forgot to rename my accumulator to state. They're basically the same thing. I'll hit save again. I'll refresh. You can now see the time is ticking away one second. When I click update, it's going by each hour.

To review that, what's going on is in our subscribe, we're getting a type whether it's hour when I click or second when one second passes by. Then we're saying store dispatch an object with the type property on it that's set to either hour a second. That comes through our reducer.

Our reducer was configured here where we say, "Grab the reducer, hook it into our store." so that when it comes through this reducer the first time, the state is set to a new date. Then from then on out, if a type comes through, we say, "Is it a second? Then do this logic. Is it an hour? Then do this logic in return."

We have that same configuration as if we're doing a start with and a scan. It's that now we can extract all of that logic, and make it reusable and portable through this clock reducer function.

HEY, QUICK QUESTION!
Joel's Head
Why are we asking?