Angular State Management Using NgRx in 2021 : Login flow Tutorial (Redux / Rxjs)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
what's going on guys welcome to tectatious my name is sahaj and today we're going to be talking about using ngrx in angular to manage state so what does state management really mean state management is mostly used to manage different states across your application so your app could be in a different state based on different actions that are happening in your components so it's crucial to manage that state and having a framework such as ngrx gives you a very powerful ability to manipulate that state as well as listen to changes on the state and perform certain side effects based on what the action that caused the state change is so ngrx is inspired by rxjs and redux it uses rxjs to mirror what redux does for react or javascript based applications so if you are familiar with redux then this should seem very very straightforward to you of course there's a certain format that's angular specific for ngrx but that being said uh we're going to be looking at setting up ngrx today step by step and uh walking towards getting an initial understanding of how ngrx works and how you can manage state in your angular applications so let's have a quick look at the diagram right here so this is the ngrx official documentation i will link this in the description down below but you can always go there this is going to be a very powerful resource for you when you set up or maintain or use ngrx um and that's what we're going to be doing in this tutorial as well we're going to be referring to this documentation and building a small example with our state management and see how kind of that works out before we move ahead i do want to request you to please like this video and subscribe to my channel if you like what i'm doing here and if you'd like to support me in bringing more content like this to you guys so for this video we're going to be looking at an angular app that i have here it's a very basic app it's a marketplace where people can put up products for sale just like a facebook marketplace uh and it has a header which has a sign-in page and in the sign-in page as you would expect we have an email input field and a password input field if i open the inspector here and if i try and make my calls with any value here you can see that it makes a call to my local api server that's running on node and of course the email and password don't match and hence the the request is not a successful uh request or it's a not a successful response but i can quickly just enter the correct credentials for a user that does exist make a call and we can see that we got a 200 because the email and password are correct here now what we want to achieve from this uh video is that instead of making our api calls directly from the component so this is the login component here i have a sign in button clicked function and as you can see it's making a call within the function uh to log in and then in here it subscribes to the response and we can do additional stuff as we want right so we could maybe display an alert saying hey login successful and you could also maybe send them to the homepage at a login successful but what we're going to show today in the video is that how you can do all of this without polluting your component code your component does not need to care about what happens next in your app based on this action all this should this component should care about is dispatching a login action and everything else would be handled by the ngrx store so even once on a successful sign-in we are on the home page we no longer want to see the sign in button and using ngrx and state management we're going to update our authentication state within the angular app and we're going to see how this header will change based on the updated state and it will no longer show the sign in button but instead it will show the user information to indicate that the user has locked it so looking at this diagram we can see that there's five major pieces to the ngrx store one is the store itself where the state is saved then we have something called as a reducer reducer is a pure function that takes in the previous state and it takes in the kind of action that caused that reducer to update the state and then it has its own logic to update the state as needed based on the action that was dispatched then we have the third component or the third piece called action itself action is as the name describes an action taking place in your component or a service that based on which you want your state to be updated so for example if we're making the lock-in state management in the angular app a successful login would be an action that we can dispatch and let the store know that hey this is an action that i am dispatching and i want you to listen to the state to this action dispatch and update my state as needed so in the login scenario the store or the reducer might update the state with the new user information that came back from the successful login it might also update the state with the let's say jwt token if that's the security schema that we're using so that that way we'll have a new state and it would be stored in the store itself and now this store is going to be application wide that means that any component or any service throughout the application will be able to access this particular state from the store so if we look at the left side of this diagram here we can see that the component has a selector defined it can listen to the selector now what it is a selector selector is a method you can define in your store to return certain piece of your state so for example if my um authentication state has a user and also a token and some other information right and um i as a component i'm all only interested in just just a token from that state so i can create a selector to return just the current token in the state and my component can be listening to that selector and uh basically every time that state is changed it would always have access to the latest token using that information will it will be able to do a lot of nicer things in our ui for example if you have a header in your app with a sign in button then you can update your header to no longer display the sign-in button and instead display some user information indicating that the user has logged in and all of this can be taken care of by your ngrx uh oil plate code and the logic that you put in there so your ngrx store is the one that's responsible for taking care of all of that and all your components need to do is either dispatch an action saying hey something has happened do whatever you need to do and the other thing that your components that need need to do is basically just listen to the new updated state and that is it they don't care about anything else uh so for example if you have api calls that you need to make or you have other ui changes or your exchanges that you need to do in your app your components can only have their own individual responsibilities they don't need to care about all these things so that makes it very easy to scale your code when your project becomes bigger and bigger it's it's better to have your components smaller and just doing one thing or one responsibility and having this logic separated and maintained only by the store is really powerful and we're going to see that in the example that we use for our tutorial today so the fifth piece that i want to talk about is effects so whenever an action is dispatched we can have an effect defined that listen to the action dispatch and do something it can do anything uh it can basically for example if you have an api call you need to make right for example um you have a login successful action right you got a login done and now at that point you want that i also need to fetch my user's uh favorite product so if we're building a marketplace and my user can have a favorite products list then whenever i log in i want to fetch and update my state with my users favorite products so instead of having to write that code in our component to listen to when a login has been done and then make that call to update the state for the favorite products of the user we can use an effect that will automatically get triggered when the login successful action has been dispatched so this is mostly used for api calls there's also other scenarios that you can use them in but most common use of them of effects is uh making your api calls based on your action dispatches so even for a login login request you can literally just dispatch a login request action from your login component and you can have an effect defined which will listen to this action and make the api call so your api call never needs to be in your components anymore so that's the brief of how ngrx works and what these major five pieces are and next up we can finally start looking at the code uh and see how we can set it up and also work with this login example that i just talked about and see how that helps us scale our apps and keeps our components and services way cleaner so let's start looking at how we can actually get started with uh setting up ngrx we can go to the walkthrough here and we can see that there's a bunch of stuff already defined here in their documentation that explains how actions can be created how reducers can be created and how we can import the store in our app itself so before we do that we do need to go and install our ngrx itself so to do that we can go to the installation here and if you're using npm you can run this script in your project i'm i personally am using yarn and hence i will go to my project and i will run that script so this is my project structure here and i am using a monorepo uh using nx or narvel and this is the root of my monorepo and hence i'm gonna run the command right here so the command is yarn add and grx slash store okay so that's gonna install a bunch of dependencies and once that is done we should be able to start using the ngrx store in our code base and there we go and before we move ahead i also do want to install ngrx effects because we are going to be demonstrating those as well so again for npm you can use this for yarn i'm going to use this uh you can also use angular cli using this ng add command but today for the demo i'm going to be using er let's go ahead and paste that here and let's get ngrx effects installed in our code base and while that's being done we can go back to our ngrx store dock walkthrough section and we can start writing uh our first action so as i mentioned before just to give you a quick overview again in the angular app we have source app and then in here i have my pages i have a login page right now the login page on the login button click is actually making the api call manually and doing all the logic that needs to do in the subscription of that call so what we're going to do is we're going to add our first state which is going to be the authentication state which is going to hold or manage all the state that's uh relevant to a user's authentication so if the user is logged in or not if it is if the user is logged in then also holding the information about the user itself so to do that we can go first thing we need to do is go to our app module and we need to import store module in our app module itself so let's go and do that go to app module and in here in the imports we can add store module and this should be coming from ngrx store oops go back here and we can literally copy this and now that we have that we have import we've imported store modules from ngrx store and we can leave this import as is for now the next thing we want to do is we want to create a directory for uh holding our app app-wide state so for the way i like to do that is create a folder called state in my app folder and then in the state itself i like to create folders specific to the state that i'm handling so it could be an odd state you could have multiple states here but today we're going to be doing the auth state so i'm going to create a folder called auth inside of state and in the odds folder i need three files i need auth.actions.ts i need auth.reducer dot ts actually i'm going to rename this to odds dot reducer and we need dot effects dot yes so now that we have that we can go and look at how angular documentation or ngrx documentation defines its actions so we can literally just copy this here and let's see so we can start by importing create action um we can do this import from the ngrx store itself so just copy that all right and in here we have so the first action i want to have for my login i want to have three actions i want to have a login request action and the format the way we define these actions the first parameter in this create action from ngrx store should be a type of the action so in here in the square brackets i'm going to say that this is relevant to my odd state and the action itself is a login request and then the other parameter is the properties this is basically the properties that we want to send with this action so whenever a component or service needs to dispatch this action they can send these parameters so a login request action would typically have email and password right because an act a login request action without these things is meaningless so let's go ahead and do that i'm going to make a credentials object and in here i'm going to say it can have an email and it can have a password and that's it this is our first action now i'm going to copy and paste this here three times we're going to change the second one to be login success change this here to login success and this action is going to be dispatched when a login was successful so if you call an api and you get a successful response at that time you can dispatch this action to update the state as needed so uh and for the properties in here we want to pass the successful response so if you're wondering where i got my auth login response import it from this is from my open api package um and um this is basically using open api's code generation tool to auto generate my angular client libraries i have a video on that if you want to see how you can use those uh the power of code gen and open api to uh leverage that in your angular apps and not have to write or maintain any of your api code uh so i'll link that to this video definitely check it out uh and then uh coming back here we have a login success action and a login failure action and then in login success we already defined the success response as the payload and in the login failure we define a string which is going to be an error so this failure is going to be triggered when there is a failure response from the login api we're going to dispatch that ourselves so now let's look at the reducer in the reducer first thing we want to do is define the state of authentication so our authentication state can have a token again this is based on the way i have my authentication set up for my project which is jwt based and then you can have the user of type user again i import this from my open api library and then i have login error and this can be a string right so this error would be populated when the login failure action is dispatched and then next thing we want to do is uh define or declare an initial state which is going to be of type stake that we defined right above and then we're just going to say that it's null by default token is no user is not and now let's actually create our reducer so to do that we can use a create reducer from ngrx store i'm going to import that here um and then within create reducer first thing you want to say is the initial state which we defined right above and then it also takes in a on function as a parameter again this is imported from a grx store and the first argument to this is actually the action that you want to listen to and then update the state accordingly so in this case we're going to listen to the login success action we get that imported from auth actions and then as the second uh argument you pass a callback which has the previous date and then it has the payload that was attached with the login success dispatch which was our login success response and then in the callback body we simply return the new state so we want to say uh get my old state and then [Music] merge that with the updated token which is going to be in our success response and we also want to update our user object which is going to be in our response dot user object and that is it that should define our reducer to handle the login success dispatch and then we can do something similar for our login failure action so let's rename this to login failure and login failures payload is actually an error so we can change that and we also need to import the login failure action from auth actions and then we simply return a new state which will have login error to be the error that was sent as payload of the uh login failure action dispatch and then these this token we want to set to know just in case uh as well as the user so this will basically help with logging him out from the app um then once you do that the last thing we want to do here is actually import or sorry export the reducer function like this and then simply return the function that we described or defined above and that's it we have our reducer defined and once we have our reducer defined we can go to our app module file in the app module file for store module we want to say for root and then we can pass in the reducers which is the states for app that the store needs to contain and keep track of so in here we say our store or state is going to be auth and then we pass in the reducer that's going to take care of all the actions for that state so for that we can import reducer from odds dot reducer and that is it and now if we go back to the login component right now we have this api call being done manually on login button click i'm going to comment that out and i'm going to inject our ngrx store in here i'm going to import that from ngrx store and now when my sign in button is dispatched what i really want to do is say that hey my store go ahead and dispatch an action which is going to be the login request action because i'm requesting a login so auth actions now we need to import our auth actions so general convention to do that is to say import all as odd actions from and the actual actions odd actions and now in the dispatch we can literally just go and say both actions dot login request and within there we can pass in our credentials so let's define our credentials here credentials have email which is user.email that we get from our input form and password which will be user dot password and in our dispatch login request payload we're going to send the credentials and that is it this should go ahead and dispatch the login request action and it should go to our auth reducer and look at the reducer for login success action and it should update the state as needed so right now our login success so if we uh i'm sorry so this actually would look at the login request so we have no reducer here for login requests because we don't really need one the state does not change when a login is requested unless you had something called a is login in progress right and it could be a boolean and then you could have a login request uh reducer here which would basically set that to true and that would help you if you want to display a spinner or something when you have your login request going but for this video we will not go into that um we'll simply display how we dispatch the action from our login component here and right now login request action is dispatched but nothing's really happening so this is where things get interesting what we could do is that we can create an ngrx effect that would listen to this login request action and then whenever this action is dispatched with these credentials it would actually go ahead and make the api call and based on the response that it gets back it will dispatch the login success action so let's go ahead and do that we'll go to our auth.effects i have these effects defined here but i'm going to simply walk you guys through them so this is an injectable auth effects class um and then in here let's look at uh let's comment this out for now and let's look at our first effect here so this is called a login request effect and we use create effect from ngrx effects package and and to understand this you need to be fond of using rxjs if you're not i recommend that you research a bit about how rxjs works and how you can use it with observables and all and then you should have a better understanding of what really happens when we do these pipes and when we use these off type or exhaust map uh kinds of operators from rxjs but essentially what's happening here is we're creating a new effect uh we're saying that this effect is uh associated with login request action so whenever login request action is dispatched so if i open the login component here we can see that on sign in button click we dispatched the login action a login request action and now we're saying that whenever login request action is dispatched this effect should be run uh so and then we do an exhaust map and then inside there we actually do our api call so aud services what i have from open api that does my actual http call and it sends in the parameters so notice how it gets the email and the password credentials from the action object so login request had a payload which was the credentials as you can see right here on the right side and on the left side here now in the login we're able to access the uh the payload there and then uh send that to our login endpoint and then we do another pipe there to get the response from our login api call and then in there when we get a successful response we dispatch a new action uh which is the login success action and we pass in the payload as the response that came back to us from our api uh and then if there was an error with the login then we catch that error and we dispatch a login failure action with the error that came back from the api and notice that when you're in the catch error block you need to return a new observable of the uh action dispatch call um but that pretty cool pretty much covers how you create an effect uh and how you can leverage that to do what you need to do from your component side of things so now if we run this code go to our angular app it's going to refresh go to sign in page and if i hit sign in here nothing happens why does nothing happen that is because we have our effects here but we never defined them we never actually imported them in our app module so they're never active what we need to do is we need to go to our app.module file in here we want to import effects module from ngrx effects package so again if you didn't do that in the beginning you can still just use npm or yarn to install this package and then you want to say effects module dot or root and in here you want to pass an array that can hold all your effect classes so you can have multiple effect classes right now we only have auth effects we're going to pass in odd effects we import that from our effects file and that is it and now if i save it go back to the application refresh it hit sign in and in my network tab i can see that a call was actually made and my parameters were sent and i got a 200 back and we can just type in some random stuff here just to make sure that our payload is sent correctly hit sign in and we had a fail response because the user does not exist and we can see that the payload was sent correctly so you can see how easier it got for our components to make api calls and do all the additional stuff that needs to be done uh without having to write a lot of code in there or even to maintain it so all our sign in button really is doing is simply dispatching the login request action and then everything else is taken care of by the effects and as well as the actions and the reducers so when a login success action is dispatched the reducer is able to update the new state sorry update the previous state with the new token and the new user that's sent in the login success payload and that explains how we're able to leverage effects and actions and reducers to make state management work for us and keep our components cleaner and shorter now for better ux um what i want to do here is that when i click on sign in and if it's a successful uh sign-in i want to display an alert and i want to send the user to the home page now you might think that we can do that in the component here itself right we can display an alert here login successful but we don't even know if the login was successful here we're not listening to that event um so we could listen to it but the ideal situation here is to leverage your side effects in ngrx so if we go to auth effects and if we create a new effect here i'm going to uncomment this and we are calling it login success effect and this effect is concerned with the login success action so whenever login success action is dispatched uh login success effect will uh take place and then inside of it we're simply just getting the payload of this login success or whatever payload was sent in this case it was the actual success response and then inside the tab body uh we're simply routing them to the home page and then we're also displaying an alert login successful welcome and then we're using the response that came back in the login success dispatch and we're using that to display the login users first name so notice that when we had a login request effect we made our api call and then if the api call was successful we actually dispatched the login success action and in the payload we pass in the response that came back and then that's the response that's been used here in the login success effect with login success response and we're using that to display the users firstly one thing to notice here is that we send a second argument here to uh create effect which is dispatch false this basically means that this effect is not dispatching a new action so this is very important otherwise you're gonna you can have a code that's stuck you're going to have memory leak and your code is basically going to be waiting for an action to be dispatched so make sure you set this to dispatch false because we're not actually dispatching an action here and now if we save that and go back to our app click sign in and voila we have a alert box that shows the name of the user and if we click ok we also get back to the home page so see how we do all of those things by just simply dispatching this one login request action in the component so our component is so short right now we don't need all those injections all we need is the input form and we need to dispatch uh the login request action and that is it everything is taken care of for us from that point on um now one thing we wanna i wanna show uh for the sake of ux and for the sake of understanding how selectors work uh see how we have a header here and we have the sign-in button here so we just logged in but we still see the sign-in button there right and we don't want to show the sign-in button if the user is logged in instead what i want to show is a button with maybe the username and a user picture maybe a menu with my account my settings and whatnot we're not gonna get too fancy with this video all i'm gonna do for this video is update the header component to uh listen to the state of authentication and hide the sign in button and instead show a button that reads the name of the user to indicate that the user is logged in and that the state management is working as expected to do that we're going to go to the auth.reducer file and we're going to create um selector here from ngrx which is going to allow us to pick up the auth state and pick up certain pieces of the aux paid auth state and use them in our components uh to do anything that they need with their ui or any kind of logic so let's go ahead and create a selector so first we need a selector to actually select this auth state from the global app state so this auth is a feature if we go back to app module and look at store module for root in here we can see that we define auth as the as the key of the of this particular state right and then when we're creating the selector for this particular auth state we can use that key to get that state so we can say select auth state equals create feature selector we get this from ngrx and then the feature selector is going to be of type state which is the state we defined here for our auth and then in here we put the name of the key for our state which we defined in the app.module file so once you do that you have access to your auth feature and now you can make custom selectors to select specific pieces of the state so for example if i only care about the token or only care about the user i can simply use those selectors to get that information in my components so let's create one for a token and we're going to use create selector this time again from ngrx and the first argument we pass to it is to select our auth state and then the next argument we get the state from the previously called select hot state and then we use that state to return the token in that state so that's how we create a selector for the token we can also create a selector for user and return the user so to summarize we select the auth state from the global app state first and then we use the create selector to uh basically select certain pieces of the auth state now that we have this in place we can head back to the header component and in the header component if we look at the template we have these buttons here and one of the buttons is a sign in button and what we want to do is uh somehow put a if condition here saying that if my user has a token a valid token then you can stop showing this and instead show a new button that would display the name of the user so let's see how we can do that first thing we want to do is inject the ngrx store um and this is going to be of type auth state because that's the state we care about to do that we can import all as from auth and you can just import that from state path and ox dot reducer so we're basically importing everything from auth reducer file and we're uh calling it from auth that's an alias again that's a that's an ngrx way of importing things from uh from your reducers so now we can say that the store is going to be of type auth state so from auth dot state next thing we need is the jwt token right this is going to be an observable and we can select it from our store now and as a selector we can pass in the selector that we created so from on dot select token so if i open my reducer file here on the right this is the selector we created and in here i simply pass in that selector i can also get my user in a similar fashion say from auth dot select user now i'm getting these separately but i could have also just got the entire state but it's usually ideal to get only what you need because there could be other things in the odd state that your header component doesn't necessarily care about so in this case i'm going to be having these two observables here and um now that we have this in place all we need to do is go to the template file in the template files sign in button i'm going to add a ng if condition and i'm going to say that display this only if the token is null right so let's do that by saying not jwt token and we are going to use angular's async pipe to get the response from the observable the actual data and use that as an ngif condition and now that we have this in place we can also add another button to the very end of our header so this is going to be the very right side and now in the ng we want to say that if token does exist right so i'm going to remove the exclamation mark and if it does exist then show this button the title of the button should be um so i want to show the user's first name so we have the user observable here user again use the async pipe to get the or get the data of the user and then we're going to say first name and we can remove this click for now and save this and let's see what we did just give it a refresh sign in sign in login successful welcome john and voila look at our header our sign in button has gone and now we have a button on the right that reads john which is also the name of the logged in user so at this point your app any component in any place of your app could access this state and do what it needs to based on the information that we get from our odd state and this pretty much shows the power of using ngrx and how we can scale our components and pages so easily without writing all those ifs and else conditions and without writing all that api code and chaining everything in our component code we can use our actions selectors reducers and effects and we can leverage all of that to maintain a very scalable front-end project more specifically angular in this case but this is a general concept of redux that other frameworks also implement um but that being said i think this covers what i had for this video um thank you for sticking around i hope you were able to follow through and i hope this helps again if you like my video if i was able to help you out please don't forget to like this video and subscribe my channel so as to support me in making more videos thank you so much and take care
Info
Channel: Techtacious
Views: 17,972
Rating: undefined out of 5
Keywords: Ngrx, Angular, Web, Development, Software, State, Manage, Management, API, requests, selectors, effects, store, redux, rxjs, components, actions, component, effect, selector, action, dispatch, observables, pipe, how, to, why, use, 13, 10, 11, 12, Typescript, javascript, modern, cloud, node, openapi, tutorial, live, code, coding, faster, scale, scaleable, efficient, ui, ux, login, register, flow, workflow, authentication, user, authenticate, header, sign in, sign out, logout
Id: EmLlk5HmUPs
Channel Id: undefined
Length: 46min 12sec (2772 seconds)
Published: Mon Dec 27 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.