In this video you will learn why do you need ngRx inside Angular and how you can bind it to your Angular application. And the first and most important question here is what is ngRx? And as you can see here I opened official ngRx website.
But from my point of view it is not exactly clear here why do we need ngRx at all and what problem it solved. So to understand why do you need ngRigs you must understand the concept of Redux. And actually Redux means that this is a state management for a single flow of data.
So we have our state, then our component can dispatch an action, then our action can change our state, and all our components are subscribed to our state to apply some changes to our components. If you don't know and understand Redux it doesn't make any sense for you to watch this video. To master ngRx you first need to understand the concepts of Redux. And actually ngRx is simply an implementation of Redux inside Angular. So what do we typically want to do with ngRx?
First of all we have a global state. We can apply some changes to this state. And all our data is in a single place.
And secondly we have a possibility to make some asynchronous things. For example like HTTP calls to our API by using effects. And we will talk about effects a little bit later.
And the question that I am getting from my students really often. Ok, why do I need ngRigs and why it is that popular if I can simply use an angular service, call it inside component and I am totally fine. And this approach is not shareable at all.
We are not talking here about state management. You are just saying about fetching some data and rendering them inside component. If you have lots of components and modules and you have a huge application you need something for state management. You need some rules how people must work with your state.
This is why Redux and ngRigs are so popular and I never saw a company who are doing Angular for example without usage of ngRigs. So enough talking, let's start implementation. So our goal is on the simple example to bind ngRigs to an Angular project and see how it works.
And first of all we must install several packages. And here as you can see on the left we have a lot of packages. We just need three of them.
First of all ng-rix store. This is a main package. It brings ng-rix inside your application.
The second is developer tools. And actually here ng-rix store developer tools is exactly standard Redux developer tools for ng-rix. And actually from my perspective this is the best tool to debug any application without digging in the code. And the last thing that we need here is ng-rix effects.
Because we want to write some asynchronous code. So let's jump here inside console and I have here a generated Angular application. So first of all I will write here yarn add ngRigs slash and we have here store.
The next package that I want to install is ngRigs effects. And the last package here is yarn add ngRigs store devtools. Now let's look on our project. As you can see here inside app I have a new module which is called post.
And the main idea that here inside component we will render a list of posts. Here I just have h1 and inside posts I don't have anything. But also here I generated a service, postService where we are getting a list of our posts. And it is simply id and title and here we are getting it as a stream with delay 2 seconds just like we are getting our data from the API.
And here I also generated post interface which is just an interface for our pose so now it is time to bind in georex store to our application and for this we must jump inside app app module and here inside imports we want to write store module dot for root and we are just providing inside an empty object and actually this will instantiate ng-rix inside our application but as you can see we are not providing anything here inside Because we want to define all our reducers and all our stuff which is related to specific module inside that module. This is why here we won't have anything. And after this it is really important to bind ng-rigs store devtools. Here inside overview you can see the implementation.
We can simply copy paste these lines from here store devtools module instrument and paste it inside our app module. And what this line is doing it will instantiate our Redux DevTools. And here maximum we can see 25 lines, we will have log only on production, and here after pause is true when our DevTools is not opened. Now we can open our application in browser and here I have a tab Redux. If you don't have this step you must just jump inside google and type Redux DevTools.
This is the standard devtools of the Redux and you will get this nice tool. And actually we see here all this stuff which actually means we don't have any state but we already created our Redux DevTools and successfully bind it to our application with just this line. Our next step will be to create a state for our posts.
So actually posts is our module where we want to work with posts. We can say that this is a single page for example. And here inside our posts, inside types, I want to create a post state interface.ts.
So the main idea is that inside Redux we have just a single global object. And we somehow want to have slices inside this object. And actually inside every single module, for example inside posts, we can create a slice. And actually this slice is exactly post state. And here inside we will have all our properties which are related to this specific module.
And the main idea is that we don't have local properties just across all possible components. We have a global state and we can see the whole state from any place. This is why here what we can write is a new interface which is our posts state interface. And actually this is our Redux interface for this specific module. And here typically you want for example is loading which will be boolean.
Because we need to fetch some data inside our post, which actually means we want to show a loading indicator. This is why here I will create this loading, and we can set it to true when we start loading of our data. After this here we will store our post, which is actually a post interface array.
And the last one here will be our error, which can be for example a string or null, and by default it will be obviously null. And if we get some error from the backend we can just save it here and then render inside a component. Our next step here is to create actions.
So what are actions? These are user events which can change these properties inside our state. This is why here inside posts I want to create a new folder which is called store.
And here we will store everything which is related to ng-rigs. And here I just want to create a single file actions-ts. And inside we can create a new function, for example, getPost. And here we are saying createAction.
And actually createAction is a function from ng-rigstore. And here inside we can simply provide a string. And actually here typically you will see such notation.
Here we have posts in square brackets and after this getPost. What does it mean? Here actually it can be any string.
But all these strings and all the sections are global. Because Redux state... is global.
This is why here people typically want to namespace all the sections with some module name. And in our case we are talking about module posts. This is why here we have a namespace posts.
And here after this we have a name of our action which is just a string. Which actually means this single line creates for us an action. Just like we are doing inside Redux. Store, dispatch and there we are providing an action. So our action is ready now we must create a reducer.
This is why here I will create a new file reducers.ts. So here we need two things. First of all we must create our initial state.
And initial state is the initial state of our module. And here we can write our post state interface that we just created. As you can see here we directly get an error that our object is missing following properties isLoading, posts and error.
This is why here we must set our isLoading and by default the state is false. After this we have our posts. And by default we don't have any posts which means it is an empty array.
And last one is our error. By default we have no errors so it is null. And with that our initial state is ready.
Now we must create a reducer which will change our state with the actions. And here we can simply write export const reducers. And here we are using function createReducer which is also coming from ngRigstore. And inside first of all we must provide our initial state and secondly our changes.
And every single change we are writing with the function on. So here we can say on for example get posts then on get post success and so on. In our case here we must import all our actions.
And typically we are importing it like this. So import star as posts actions from and here is our file actions. Which actually means we are taking all our export const here and we can have like 10 or 20 of our different actions and we are grouping them in this single object. And now here inside on we can simply write postSections.getPost.
And this is exactly on. what we want to react. And the second parameter here is a function where we are getting access to our state.
And what we want to do inside we want to return a new state. This is why here I will spread our state and change its loading property to true. Because this is the start of our getting pose and here we want to show the spinner that we are loading something. So this is how we typically write our code. Inside create reducer we are passing initial state and then we will have lots of ons.
And here we are saying, okay, when our action getPost is happening, here what we want to do and how we need to change our state. So here we are describing all changes to our state. And here, as you can see, we have access to our state. This is exactly this state. And here we just want to update our isLoad into true.
And the last thing that we need to do here, we must inject our store module inside our post module. This is why here inside imports I want to write store module dot and here we are using not for root but for feature. And inside we can provide a feature name. And we are writing here post module which means here we can write that this is a post string. And now here we must import our reducers.
And actually we have our reducers from store reducers. So what this line is doing it will create for us a new slice of these reducers inside our state. Let's check this out. As you can see I don't have any errors.
I will jump here inside browser. And here is my state. So here inside Redux DevTools directly I see the global Redux state.
And as you can see here we have a post which is just our slice that we created. And here inside we have is loading, post and error. This is our initial state.
This is because of the single liner where inside we put our reducers. and our reducers here is saying that this is our initial state but now the most interesting part we want to change our state this is why what i want to do here inside our components pose post component i want to dispatch this get pose this is why here what we can do first of all implements on init so we want to do something on initialize here is our engine in it and we must inside constructor inject store and actually this store is our store from ng-rx and we must inject here this store to write store dispatch this is why here now we can write this store dot dispatch and here inside we must provide an action and typically you will write it exactly like we did it inside reducer import star as and here we have a post action from and here we want to jump inside our store actions and now here inside of this store dispatch we are providing posts actions dot getPosts and round brackets. So inside plain Redux you typically write store dispatch and your action. This is exactly this. Here we have store which we are injecting through ngRigs and we are dispatching our action.
So on initialize of our component now as you can see we are getting getPosts which actually means we want to fetch some data. And actually here inside state you can see that our isLoading is in true which actually means this specific action is actually in true. changed our state. And here we can click on the div tab and we see that our isLoading was changed from false to true because of this action.
Which means it is really easy to debug. You can simply open Redux DevTools, you see the list of the sections, you can simply click between them and you can see every single action and how it changes your global state. You don't need to console.log any properties, the whole state of your application is just for you here on the glance. So, this is the basics of using ngRigs. You are creating reducer for your specific module and you are creating actions that can change state.
Now the question is obviously how we can use this state inside our component and how we can render for example this loading state. This is why here we must use selectors. And if you remember what are selectors from Redux, this is the way how we can select some properties from our state. And we have something similar inside ngRigs. This is why here inside our store I want to create the file which is selectors.ts.
And here we want to create selectors for different properties of our state. And actually first of all here we want to select our feature. This is why here we can write a function select feature. And here we simply get the global state of our application. And typically we'll have here app state interface.
And then after this we want to return state.post. So what this line is doing at all? Actually here we will have like hundreds of different properties because you can have hundreds of modules like maybe pose, authentication, users, whatever. you prefer.
And actually here we want to get just this slice of posts because only this single slice is related to our page. Actually you could get any slice but for now we are interested in this specific slice. This is why here this select feature is just selects a single feature state.post So now let's talk about this app state interface.
What is this? This is our global state. This is the whole representation of the state inside your application. This is a single point of truth.
And what we can do here inside our app, we can create new folder types, and inside we can create our app state interface TS. And this is exactly the place where we will create this interface and where inside everything will be situated. So here we can just export this interface app state interface.
And what we have inside just a single property post, which is our post state interface. We already created that. And actually now any developer can just jump inside our application, open this single file and see the whole global state of our application. And now he can just say, ok, I am interested in this post state interface. And he is opening it and he sees all these properties.
And now we can jump back inside the selectors and import here this app state interface on the top. So here app state interface from source app types app state interface. And actually here we are getting nice autocomplete and we know that we are totally right.
We have a slice post. And actually this is just a helper to get a specific field from our slice. This is why here now let's say that we want to get isLoading.
This is why here we can create isLoadingSelector. And for this we are using createSelector function. And this function is also coming from ngRigStore.
And what we want to write inside this select feature. that we just created on the top and secondly we will have a function and here we are getting our state and as you can see here state dot is our slice we have here access to three properties is loading error and pose and here i just want to return our state is loading which actually means this line creates for us a selector that we can reuse and it is a stream which will deliver for us our data This is why I want to copy this is loading selector and use inside our component. And here inside our post component yes inside our constructor we can use this selector. And for this we can write this store select pipe and inside we are providing select function and it is from ng-rig store and inside we are writing is loading selector.
Which actually means this line selects for us is loading selector property from our state. And now here we must assign it because this is a stream. We can save it inside this isLoading with for example.
And here we must create this stream. This is isLoading which is an observable of boolean because we know isLoading is a boolean. But as you can see here we are getting an error from typescript.
Here it is written that type observable object is not assignable to type observable appStateInterface. And the problem is here that we didn't specify inside our store what state we have. And here inside store we can actually say appStateInterface. And in this case we won't get any error, because by default inside this store this state is simply an empty object.
It is not suitable for us. This is why here we are saying ok, this is our global state, this is why is loading in this case is just a stream. And now this single line will return for us data from our state. This is why here I can jump inside HTML and just use this stream.
So here we have div with text loading and here I can write ngif condition. So ngif and here we are using our is loading stream with and we are using here async pipe. Because we are using async pipe we don't need some subscribes, we don't need unsubscribes. Now I can jump inside browser and reload the page. And as you can see here we directly see this div loading.
Why do we see it? Because actually inside our application inside Redux inside our state this property is loading is set to true now and when it will be changed to false then our component will be rendered directly. And now we must to talk about asynchronous data and asynchronous effects. Because now you already know everything about dispatching, reducers, actions, but obviously you want to get some data from the backend.
Which means you have some long asynchronous operation. And this is exactly what we have here inside our service POST SERVICE. Because here we have a delay. So how it works inside ngRigs exactly like inside Redux, for example with Redux Thang.
We are just dispatching an action at the beginning of the fetch and then we dispatch an action at the end of the fetch. This is it. And this is what we need to implement.
First of all we want to jump inside our store actions and create here two additional actions. This is why here I will copy paste getPost twice because here we want getPostSuccess and getPostFailure. Because for a synchronous code we need start, success and failure. So here will be getPostSuccess.
And here will be getPostFailure. And now here we can change the name to getPostSuccess and getPostFailure. But it is not all because actually here we want to provide some data. Here we are getting something from the backend and we need to notify about this data inside our state. This is why here as a second parameter we can provide props.
And as you can see we can auto import props here and inside we must say what data we will get back. And typically we will write here an object with field for example posts and here post interface array. Why like this? Because actually from our API we will get a list of posts as an array.
And now here we have a failure. We also want to get an error from our backend. This is why here we will also write that we have props.
And inside here we can write that we have an error. This is why here will be an object, error field and it is a string. So this is how you typically create actions with some parameters.
And now we want to change our reducer. So we must jump here inside reducers and here we have onReaction. But now we also want to apply it to success and failure. This is why I will copy paste it twice, put here commas and now let's change it to getPoseSuccess and getPoseFailure.
Now what we want to change in our success first of all is loading must be set to false and secondly we are getting here our pose. And actually we are getting them inside our action. And this is the second parameter of this function.
So we are getting here state and action. And what I want to write here is pose. Which are equal to action dot.
And here I am getting pose. Which actually means we are dispatching the action with pose inside. And here we are updating our state with this pose. And exactly the same we are getting inside failure. Here we have access to our action.
And this loading must be set to false. And we want to write an error inside. And it is action.error. And I am sure now that if you don't know ngRx this code is really overwhelming for you.
But actually it is always the same. You always create actions, reducers, selectors and they are all looking the same. This is why you simply need to implement it like 5 or 10 times and then you are good to go.
So we successfully updated our actions and reducers. Now we must update our selectors. So here we already have is loading selector and I can copy paste it twice and change first of all because we want to get here our post selector and here we can simply get from our state state.post and last one here will be our error selector and here we want to get from the state.error. So now everything is prepared and we must start talking about effects. So what are effects?
This is a possibility to make an asynchronous calls inside ngRx. This is why here inside store I want to create one more file which is called effects.ts and inside we want to create an effect. And actually we are creating it inside a class.
This is why here we can create posts effects and on the top we should not forget injectable. Now here inside we want to create for example get posts and the name here doesn't matter and it equals our create effect function. And inside we must pass a function.
And now here it will be difficult because actually inside effect because they are written with Rigs.js it is really easy to make a mistake because we have just a lot of brackets and indentation. So what we are doing inside create effect is we are returning this dot dollar actions and we don't have here dollar actions this is why we must inject it here. This is why here we have constructor and we're injecting our actions with dollar and it is actions which we are getting from ngRig's effects.
And after this we can write this dot and we have access to actions and this is a stream. And after this we are writing pipe with off type inside. And actually we are using here off type because we want to to react on the specific action.
This is why here on the top we must import our actions. And this is import star as our post actions from and here are our actions. Now inside of type we can provide post actions dot get post. Which actually means this effect will take place only when our get post actions is happening. And now after of type we want to write merge map.
And inside mergeMap here we want to return a function. And what we want to return here is a call for our service. This is why here we must inject our service. So it will be private postService and it is our postService.
Now here inside mergeMap we can use this postService. So this.postService.getPost. And this is a stream and we must react for it. This is why here we can again write pipe.
And inside we have a map. And here we are getting access to our posts. And we want to dispatch a new action. It will be posts.action.getPostsSuccess.
And we are providing inside our posts. And actually here we should not forget our brackets because we are providing inside an object and not just array of posts. So this code might be really scary for you but this is the same code that we are writing again and again inside effects.
We simply create here an effect and here we always write this actions.pipe. of type and here we have some action. In our case this is the starting action getPost. And inside here we have a merge map and we want to return here a stream.
This is why here we are calling this post service getPost and this is actually a stream which is returning for us data from API. And here we want to react to this stream accordingly. This is why we are mapping here our stream and we want to dispatch an action success.
The main point is that we are not writing here this store dispatch, but we can simply return our action and it will be dispatched accordingly. And now after our map we can write here catchError. And inside catchError we are getting an error. And we want to return a stream again. This is why here will be off.
And inside we are pasting pauseActions.getPauseFailure and we are providing inside our error. And here is an object with an error which is actually error.message. Which actually means we have here success and failure.
So here we have a stream with map with success and here is sketch error with error. And here when it is failing we are calling getPostFailure. And actually this code of effect you will copy paste 99% exactly the same to every single file.
So our post effect is ready now we must register it inside our post module. This is why inside post module here after store module We can register it with effects module dot and here we have for feature and inside we are providing an array. And here what we can write is our pose effects that we just created. And we should not forget to register effects module inside root.
This is why we are jumping inside that module and here after store module for example we can write effects module dot for root and this is it. We are not providing anything inside. Let's check this out. We don't have any errors here. Now let's reload our page.
And this is how our Redux is looking like. We have here getPosts and getPostsSuccess. How it happened? Actually we wrote inside our component just getPosts.
This is what we can see here inside our Posts component. Just this store dispatch. And actually this triggered our effect.
And our effect called our service which is an asynchronous call to our API. And after this call is ready, after 2 seconds, we are getting getPost success because it is finished. And this is how we changed our state.
So our isLoading is changed from true to false. And these are our posts. This is why now inside our state we have isLoading false. This is the list of the posts that we can use now. And this is the error it is null.
Because we are not in failure. Now let's render this information inside our component. So here we need two more things.
First of all an error. which is a stream and here is our observable of an error. This is string or null. And we also need here a stream for our post which is an observable of our post interface array. And here inside constructor I can just copy paste this loading twice and rename it first of all to the error and secondly to post.
And here we can use another selector it is our error selector and here we will have our post selector. So this is how we are getting our data from the state. And now we can directly use these streams inside our HTML. So first of all let's render an arrow. We can simply write here ng-if.
We are getting here an arrow stream with a sink as arrow. In this case here we are getting a local property arrow that we can directly render. And after this we can render a list of our posts with just ng4 loop.
This is right here. ng4. We are getting access to every single post.
of our stream post which is a sync. And here inside we can just render our post.title. Let's check if it's working. I will reload the page and we can see here loading for 2 seconds and after this we see our posts because they were fetched, put in state and now our stream was changed and our component was re-rendered.
So as you can see when you are using ng-rix code you don't have any business logic inside your component. You simply have here dispatches And you have subscriptions to your state. This is why it is extremely efficient for big scalable applications.
And actually if you are interested to learn how to use animations inside Angular make sure to check this video also.