⚠️ This lesson is retired and might contain outdated information.

Set Up ngrx Store for an Application Feature

Lukas Ruebbelke
InstructorLukas Ruebbelke
Share this video with your friends

Social Share Links

Send Tweet
Published 6 years ago
Updated 6 months ago

The first step to migrating to state management with ngrx store for a feature is to instrument that feature with a basic reducer and then wire it into the top-level reducer which is registered with an Angular module. In this lesson, we are going to show how to define the shape of your feature state with an interface, define initial state and then set up the most basic reducer possible to work with the store. We will then add our newly minted reducer to the top-level reducer which then registers it with our state module. From there, we will modify our feature component to hydrate itself from the store and not from a service call.

Instructor: [00:00] In this lesson, we are going to get started integrating NgRx into our application by building out the projects reducer. We have some initial data here that we'll use in just a moment for our initial state, but the first thing that we need to do is we need to define the shape of the state for our feature. Think of this as almost a table definition.

[00:25] We're going to define an interface called projects state. We're going to give it two properties. The first one is going to be projects, which is going to be just an array of project objects. The second property is going to be selected project ID. We can keep track of the ID of the currently selected project, which is either going to be a string or, if no project is selected, then null.

[00:52] Now that we've defined the shape of the state, let's go ahead and define our initial state, which is going to be of type project state. We'll define initial state. Then we'll strongly type it to the interface that we just created.

[01:09] We'll go ahead and set projects to initial state. That's the data structure we saw just at the very beginning of this lesson. Then we'll set selected project ID to null.

[01:24] The next thing that we need to do is define the simplest possible reducer that we can. A reducer is just a function that takes state and an action. Based on the action type, it's going to perform some transformation and return new state.

[01:43] We'll go ahead and define our projects reducer. It's going to take two properties, state, which we will initialize to initial state, and then an action parameter as well. This is always going to return state. In the case of the project's reducer, it's going to return project state.

[02:07] Internally to this function, there is a switch case that evaluates the action type. Then based on the action type, it will do some operation. We're going to define the default case where it's just going to return state without doing anything at all. We're setting it to initial state. Then we are returning that for our application.

[02:31] Now that we have defined our reducer, we need to make it available to the rest of our application. We'll go into the index.ts, which is just above that. We're going to import our reducer. We're going to call this from projects.

[02:51] As you have multiple features, you can have multiple states for that feature and reducers. We're going to update the overall app state and add in projects as well as add in our projects reducer into the action reducer map. Essentially, what we're doing is we're combining all of the reducers into one top-level master reducer.

[03:16] Once we've defined that, then we'll go into our state module. We'll see where we would register our reducer if we hadn't already. That's in store module.forroot. We'll pass in the reducer's import. Because we're adding in the projects reducer into the top-level reducer, this is automatically going to be added.

[03:46] We'll hop into our core data module, which is the lib that our state is living in. We'll go ahead and import our state module so that whatever project is using the core data module that state is available for that. Let's go ahead as well and define an entry point for our project state.

[04:14] In the top-level barrel roll for this lib, we're going to export projects state and make that available for whatever application that we're going to have that's going to be using the projects state feature. Now that we've exported that, we're ready to integrate this into our application.

[04:40] Now we'll hop into our projects component. The first thing that we need to do is we need to import the NgRx store into our component. We'll go ahead and create a new line in the constructor call. We're just going to define store. We'll import store. Then we'll set the generic to projects state.

[05:09] Now that we have the store available to us, we are going to go ahead and set our projects observable stream to the initial data that we defined in the reducer. We're going to go this.projects equals store.pipe because this is an observable stream.

[05:30] Then from there, we're just going to select projects off of this observable stream. What this is going to do is grab the project state object from the store and return it to us.

[05:45] Let's go ahead and comment this call to the service. Let's go into our template. Let's make one small change here so that we can see what we're working with. Obviously, the project's observable stream is to be consumed by the projects list. We'll comment that.

[06:07] Instead, we're going to go ahead and add a pre-tag. We'll just go projects async, obviously because it's an observable stream, and then JSON. We're just going to dump this out into the browser for just a moment. So we can see what is happening.

[06:22] If we hop over to the browser, you can see that we're getting the entire project state as it was defined by the interface. We have projects and selected project ID. What we really want is this projects collection. Because it's an observable stream, that is easy enough to fix.

[06:41] Let's go back into our constructor here. We're just going to map project state to just the projects itself. Just doing a simple map operation, we're passing in project state. We're just going to return projectstate.project. We'll go ahead and save this.

[07:06] Then, let's hop back into the browser and see what we are returning. This is exactly what we need, just the collection of projects. We can uncomment out the projects list because we now have the data that we want coming from NgRx and not from the service.

[07:26] Let's refresh this. This is exactly what we need. We've basically replaced the service call with a very basic implementation of the reducer.

[07:36] Just a quick review. The first thing that we did is we defined our project state, then initial state. Then we wired that up into a projects reducer that takes initial state. We're setting that to initial data structure.

[07:54] Then from there, within our top-level reducer, we modified application state to include project state. This is like an interface of interfaces. Then, we updated the top-level reducer to include the projects reducer, which then was registered in store module for root.

[08:16] We added in the state module into our core data module, which then makes that available for any application that's using the core data module lib. Then we exposed our project state or the entry point to that by exporting project state in the barrel roll.

[08:43] From there, we went into the projects component. We imported the store. From that import, we were able to then select the projects off the store and then map the project state to just the piece that we wanted to use. By creating that reducer, asking it initial state, we were able to pull that off, and then, from there, bind that into our template via the projects observable stream.

[09:21] These are the basic steps that you need to do to integrate NgRx into a feature within your application.

Nick
Nick
~ 6 years ago

Do not understood why do we need to export state in index.ts if we already added it as module refference inside app.module.

Lukas Ruebbelke
Lukas Ruebbelkeinstructor
~ 6 years ago

Good question Nick! We need to export it in index.ts so that it gets bundled at the language level. This eventually gets resolved when by the end of the series but definitely a confusing thing when we are dealing with modules at a framework AND language level.

Nick
Nick
~ 6 years ago

Thanks a lot, Lukas. I was able to meet flux in vue.js, but vuex is a little bit different from ngrx, aso I will try to learn ngrx by your tutorial. Thanks for a good work!

Lukas Ruebbelke
Lukas Ruebbelkeinstructor
~ 6 years ago

Thanks Nick!

Kevin Clark
Kevin Clark
~ 6 years ago

Hey Nick. You build a map and setup reducers using StoreModule.forRoot

I assume you can also individually setup reducers for a state using StoreModule.forFeature

For example,

StoreModule.forRoot(mapOfReducers) or StoreModule.forFeature('projects', fromProjects.projectsReducer), StoreModule.forFeature('customers', fromCustomers.customersReducer),

Does it matter which way you want to set it up?

Greg
Greg
~ 6 years ago

What is a barrel roll? (First time I've heard that term)

Lukas Ruebbelke
Lukas Ruebbelkeinstructor
~ 6 years ago

Great question! The idea is that you export everything in a single index.ts which allows you condense your imports to look like import { A, B, C } from ./somewhere instead of having to import everything one by one on a new line. You are essentially rolling up your imports into a single file. Hope this makes sense!

Babafemi
Babafemi
~ 5 years ago

Hi Lukas, Please how did you generate the state module? was it a regular ng Module? I can't find it in the github code as well. Thanks

Nathan Strong
Nathan Strong
~ 4 years ago

Hi Lukas, I am having trouble with selecting the store slice 'projects' and then mapping it to the projects list. The code from projects.component.template:

this.projects$ = store.pipe(
  select('projects'),   
  // Typescript believes the result so far is type Observable<Projects[]>
  map((p: ProjectsState) => p.projects)
)

The problem is that TypeScript is thinking that the operator <b>select('projects')</b> is returning an Observable of type <b>"Observable<Project[]>"</b> rather than type <b>"Observable<ProjectsState>"</b> and so will not compile if I try use the map operator map(p => p.projects).

Do you know where the <b>select('projects')<b> is getting this wrong type assertion? And how to fix it?

Thank you very much.

Lukas Ruebbelke
Lukas Ruebbelkeinstructor
~ 4 years ago

Hi @Nathan - can you put your code into a Stackblitz so I can take a look? Thanks!

technokon
technokon
~ 3 years ago

unfortunately ng serve does not work

Markdown supported.
Become a member to join the discussionEnroll Today