Learn Better State Management in React with MobX

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey there today we're going to take a look at how i use mobx a popular state management library and a new react project to implement authentication with a json web token and we're going to use a back end that i've already developed in a previous video we're going to use mobx to store the access token after we retrieve it from the back end in the ui we'll have a login model like this as we see and then after we log in our access token will be saved in the application in local storage so that when we refresh the app the token is persisted and i'll show you how to set up a store in mobx so that we can use this access token anywhere we need so let's go ahead and get started okay so before we actually start building out our authentication on the ui we're going to need a back-end service running that will be able to provide our ui with an access token so in order to do this i'm going to be running the nest js server that i've done a tutorial on in one of my previous videos um so i'm going to go ahead and clone that repo and i'll put the url in the description so i'm going to clone that repo i'm going to check out into that folder and i'm going to check out onto the auth branch because that's where the authentication code is and then from there i'm going to run a yarn and then yarn start dev so that our server will be running so if i open up the backend server in vs code we can see that our user service is just a hard coded list right now so in our example that we walk through we're just going to use this in-memory representation of an example user so i also have this auth folder set up which contains all of the logic to get a token back if you provide the correct email and password like i said before one of my other videos goes through this uh in depth so for now i'm going to go ahead and just make sure that when we launch a request to the back end uh the the route is auth login and we pass that email and password that we have hard coded in memory right now when we shoot that request off after we start the server we are in start dev so once the server starts up and we go back into postman we should be able to send this request and get back an access token and this is important because the react application will be sending a request with an email and a password and getting that access token back so we're gonna have to use this access token future requests to authenticate ourselves and tell our backend server that we are who we are saying we are so with this back end service in place let's go ahead and actually start building out the react ui okay so in order to bootstrap our application we're going to use create react app which is a cli that will set everything up we need to start a new react project up so we're going to use mpx create react app and then you can call it whatever i'm going to call this react off and i'm also going to use a typescript template because i want to have my rack code in typescript so the first thing i'm going to do actually is open up the react auth project in vs code and in my react start script i'm going to go ahead and just add uh at the start of the script here i'm going to add port is equal to 3001 and that's because my sjs server is on listening on port 3000 already so now if we start the reacts development server which so if you open up your browser and go to localhost 3001 you should see the react starting page so now we can go ahead and open up the project in bs code okay so the first i'm going to go ahead and do when i open up is just get rid of all the starting files here uh i'll get rid of the css file and the testful file that automatically gets generated i'll get rid of the testing and web vitals code as well as i'm not going to be using this i'll go ahead and get rid of the logo this boilerplate css i'm not going to need it so all we're left with is the index.tsx so we'll get rid of the web vital usage here and so i'm actually going to go ahead and remove everything in this app.tsx and then make sure we're actually still importing react from react um but i'm going to declare a const here i'm going to have a functional component of a type react.functional component and then in here this is just how i like to structure my components so we'll have just an empty div right now and then i don't want to use default exports i just prefer to have named exports so we go back into index.tsx and just make sure that this import gets updated and just make sure we move our import to the index.css up here so in order to store application state in our react app that is to maintain an access token and to allow our requests to be authenticated over the lifetime of our app we're going to need some sort of state management and i'm going to use mobx for that because it's a great small lightweight library that'll allow us to maintain state in our application in a very flexible way i'm going to add mob x so if we type yarn add mob x so make sure we also add mob x react light which is a react adapter for mobx now with the concept of mobx we have the idea of creating stores and these stores will be classes es6 classes that will store and store our data but also provide methods to manipulate and and use that data so it really allows us to program in a very object oriented way which is something i really like about uh this library so to see a closer look at this in the source directory i'm going to create a new directory called stores and this is where we're going to keep all the stores and all our attitude i'll create another directory here called components i'll actually go ahead and move my app component in there i actually just create a new folder called app this is kind of how i like to structure my my projects and i'm gonna rename it app.component.com i'm a fan of this naming convention here so then we can see in our index.tsx the import automatically got updated so the store that i'm going to go ahead and create is called the auth store so it'll be called off.store.ts and this is just going to be a class that i'll call off store and this class will contain all of the functionality required around authentication in my application so what mobx allows us to do is declare properties on this class or object which is what it'll turn into it allows us to turn these properties into observables so we can declare private properties and tell mob x that when these properties change our rack components should then react to that change in state and then update accordingly so there's kind of a manual way to do this where we can define the properties or instead we can have mob x do this for us uh and to see what i mean by this they have this function called make auto observable which will take in the which takes in the this keyword uh as a parameter so that it takes all the properties of the auth store and and makes them observables and automatically detects our methods that will mutate these properties so that our react components will update so we just need to make sure we import this make auto observable from mobx so in this case i'm going to have a private field called authenticated and it's going to be false by default but what's great about mobx is it allows us to still have our data hiding and have private properties on a class and then we can introduce getters so so we can introduce a a separate method here called is authenticated that clients or our application will call to check if we are authenticated and all we're going to do is return this the authenticated so this way no one can mutate this this property authenticated except for the auth store itself and when this property does change the make auto observable will make sure that our components that are listening to the auth store get re-rendered and we'll see how this connection takes place in a little bit so this is great we have this concept of stores now and we'd have a store for anything in our application for notifications users uh any sort of domain entities you have in your app you can have a separate store for it and you should as you want to keep this logic as separate as possible uh but then the question comes okay how do we uh how do we use this store or or how do we inject it uh into our components and i find the best way to do this is to use react's context api and what that will allow us to do is have one object that is passed down to our components so in this case that object will contain all of the stores and all the state we need in our app so let's go ahead and take a closer look at this i'll create a new file here called store.context.ts so if you're familiar with dependency injection this is uh this store context here is what we'd call the composition root so this is where in the application we are going to instantiate all of these stores that will be injected into our components via the context api so let's go ahead and create our first store so we have our auth store here and we'll instantiate the new all okay and the next i'm gonna declare an interface here called i store context because this will be the interface of our store context and each entry into this store context will be a separate store so in this case we have the auth store and so now we can actually export our store context which is our shared application state which will be accessible in our components so we're going to call react dot create context and make sure we import react so create context takes a uh type takes a type here and we can pass in the i store context so that we have type information and then we're just going to pass in an object this is the shared state with the auth store so now we have this store context we have this composition root where we're going to instantiate all of our stores in our application right when the application starts and we're going to export this so that our components can consume it so to see how we can actually use this store contact we've just created i'm going to go ahead and create a new folder under our components directory called off and this folder will contain all of the components associated with our authentication in the ui in this example i'm just going to try to present a dialog ui dialog to the user if the app detects that they are not authenticated and at that point we're going to ask the user to log in so that we can ask our backend for an access token so i'm going to create an off dot component it's got a similar structure to our app component so i'll just copy this boilerplate over so i'm going to change the name of this component to auth view and the reason why i'm going to do that is because i'm going to declare a new const down here and call this const off and i'm going to use observer and observer we import observer from from mobx react and what observer does is it takes the react component that we supply and it automatically subscribes or listens to any change in state from those observables that we set up elsewhere so in the example here in our auth store the observer listens for any properties that are marked as observables and that are actually used in the component and when those properties change it it re-renders the component so our ui will update so it's very efficient only the components that it detects the change in will actually re-render which is a great advantage of modbx so now we can export the auth component here and now in our auth view component we can get access to the store context so i'm actually going to restructure the auth store then we can call use context from react and pass in the store context so now we have access to the auth store inside of the alt view component which is great so i can actually create a variable here called authenticated and set it equal to off store dot is authenticated so now whenever uh the authentication state changes in my auth store this const here will change because that's an observable that we're listening to and when this value changes our ui will update so let's go ahead and implement this simple dialog that will prompt the user to log into our app so in order to build a quick dialogue and and some nice looking input fields i'm going to make a use of material ui which is a great react ui library that lets you create some really great components that look and work great out of the box so if we look here it's a quick one line install here with yarn i'm going to copy this line here paste it in and we're going to add material ui okay so back in our auth view component here i'm just going to go ahead and paste the example from material ui docs and we're going to import the dialog component from material ui so we're just going to open to true to make sure we can actually see the dialog in our app component now i'm going to go ahead and instead of returning an empty div we can actually return our auth component so after we include the auth component here back in the auth component actually we're going to make sure we include some children so that the dialogue will actually appear so i'm just going to put in a paragraph tag and say this is a dialogue and once we save it we should see uh a pretty ugly but we should see the dialogue in our react app so that's great let's go ahead and actually flush this out a bit more so first of all the open property is going to be whether or not we are currently authenticated so if we're not authenticated that's when i want to show the dialogue okay so next we're going to need some text fields so that we can get the users login and password or email and password so i'm going to import similarly a text field from material ui and instead of this paragraph here we're going to create a text field we're going to create a new text field component and we're going to give it a label of email and we'll do the same for a password field right below okay so i want a little bit of css to this modal just to give things a bit of space so add an off.style.css and this will just be a style sheet just for this component so i'll add a container and i'll give this this dialogue a container padding let's say 30 pixels so this is going to be a surrounding div around our inputs so i want to make sure our display is still set to flex and our flex direction is column so now back in here let's go ahead and create a surrounding div and we can give a class name of container to the div take these text fields here we're going to copy them inside div and then and just make sure we add a dot forward slash here um and then looks like i just added some unnecessary uh quotes here so make sure it displays flex and then uh i'll add a class for the actual input themselves so i'll have a class for text fields and i'll give this a margin of 15 pixels so now in our auth component we can give a class name to these guys here so now if we take a look at our react app we should see a little dialog with an email and password fields which is great let's just go ahead and finally add off finish this off with a button so import the button from material ui and then we'll have the component in down below so let's actually um introduce some state here so that we can maintain uh the email and password and change them correctly so uh local state use state the eustate hook is still a great candidate for this kind of local state really we only want to use mobx for state that needs to be shared between components in our application but uh if it's state that just belongs to one component we can still use use state to uh hang on to this state so let's do that we'll have uh an email and said email and call use state import it from react and we'll also have password and set password and we'll call use date so now we can provide values and we can pass in the email and we can similarly pass in a value for the password we can also specify uh on change so on change we will get the new value and we'll call set email with that value we'll go ahead and do the same thing for password we'll call uh call on change and we actually want to make sure that we're not passing the value because this is the event change object so if we want to get the new value we'll call i will actually call this the event and then we'll we'll call the uh or pull out the dot event.target.val and that will be the new value and we're also going to empty strings as the initial value for both of these just to make typescript happy so we'll do the same thing for the password this will be the event and we'll pass an event.target.value so now when we change the password in the email our state should be updated and we should be able to see the change in the input fields themselves so let's go ahead and try that out test example.com and some dummy password so we can also pass the type field to these inputs just to give a little bit more information to the system that's using them so we see for the password after we provide the password we should now see that our password here has protect so next we need to add some logic so that when we click our login button our auth store makes a request to our backend service with the user's credentials uh checks to see if that's a valid login and then returns back an access token so we can authenticate the user and make future requests so let's go ahead and implement that now back in our off store so in order to implement the functionality of our off store being able to reach our backend and log in i'm going to introduce the concept of services in this architecture and the services are going to abstract away um any communication with the back end uh just to keep that code separate from the store itself so what i'll go ahead and do create a new folder services and we're going to see in a second here how i set up these services such that it's very easy to inject a service for each given store and use that service to communicate with the backend service and also will have authentication taken care of so let's take a closer look at this so the first service we're going to need is an auth service okay and the option so this auth service is going to be responsible for uh reaching out to the back end and getting the access token we need so i'm going to export a class called auth service and we're going to have one public method called async login okay and it's going to take a login request of type login requests okay so we need to define what this login request will look like uh and because we're using the nest js auth backend that i've created in an amount of my previous videos we know what the shape of this uh login request is going to look like so i'll create a new folder called dto which stands for data transfer object in here i'll create another folder called request and this will hold all of my request data transfer objects which are just going to be an interface which describe the data that i'm transmitting to my backend service so we'll create a login request.dto we'll export an interface called login request and we're going to have uh two fields of course we're going to need the email which is a string and then we're also going to need a password which is a string so these are the two bits of information we need to log into our backend service and get an access token so now we can import the login request and now i'm going to get a const here response and set it equal to a weight we're going to use the fetch api to be able to reach out to our back end now i'm going to get an api url which so we're going to import so i'm going to need to include the api url here and this will be local host when we are running locally but i want to be able to swap that out for a production url when i'm building for a production environment so to make this easier what i'll do is i'll create another folder called utils and in utils i'm going to create a url.ts this will just be a list of url related cons constants that i'm going to export okay and i also just realized we've created the auth service in the stores folder make sure we move it into the services folder so i'm going to go ahead and export a const this will be a constant api url so we will swap this out uh accordingly if we have a production url we can put that here but being able to have this in one spot makes a lot easier to swap it out so if we're running locally i want to use localhost slash 3000 so now back in the auth service i'm going to import api url we're going to call off slash login which if we recall from the beginning of the video is the same url we used in postman and remember we used that email and password to obtain the access token so we're going to reach off login this is going to be a post request and then we can specify some headers here we know that the content type is going to be application slash json and the body is going to be the stringify login request that we have up top so now that we have this raw response we're going to go ahead and parse it so i'll create a new const pars response and we'll call await response.json to take the json in order to convert this uh raw uh response which is just a stream coming in from the back end i want to convert it into readable.json and then i'm going to do a quick check to say that if the pars response is not okay and this okay is part of the parts response after we turn it into json i want to throw a new error and i'm going to throw the parse response so that we can catch this higher up in the stack lastly i'm going to return the parsed response and before i move on here to make sure we actually change this to if the response is not okay because the the okay property will be on the response object itself not the parsed response so now that we have this auth service set up we can go back to our auth store and in the constructor we're going to have a very similar structure to if you've used angular before i like to practice dependency injection such that we can list out all the dependencies that each store is going to have in each service such that if we need to swap out an auth service for a different one as long as they conform to the same interface we can do so at the composition root which is what we will see in a second here so to make this a bit more clear in our constructor we're going to take in the auth service and now we can create a new async login method we know this is going to take a login request it's going to take the username and password from the auth component so we're going to create a new const here i'm going to call it token payload data transfer object okay and it's going to be await this dot off service dot login and we're just going to pass in that login request so now that we have the token payload i want to be able to save the access token that we've gotten back in the browser's memory and in order to accomplish this we can use local storage so i'm going to call local storage dot set item and what this will do is it allow us to process the access token even if the user refreshes the application which is great so they don't have to log in every time it's only if they clear their uh their browser storage then they'd have to log back in so i'm going to call set item i'm going to use access token here as the key and then as the actual value we're going to call token payload dto and we're going to get the axis token off of that now the last step in this method is that we want to set this dot authenticated to true because we know the user successfully authenticated at this point now with mobx when you work with asynchronous methods you can't mutate class data directly in the async method because of the nature of how mobx reacts to asynchronous updates there's a few ways that they recommend changing or mutating class data in an asynchronous method and if you want to read more into it i'll include the link to the description in the docs but the one of the ways we can get around this and so the way i get around this is by using separate class setters for the class data so we can just have a private setter called set is authenticated or we'll say set authenticated it'll take in authenticated which is the boolean and we're just going to call this authenticated equal authenticated so now instead of directly mutating the class data here we'll call the distance that authenticated and pass true and one last thing i want to do is i want to actually wrap this whole uh this whole block here into a try catch statement because if for some reason our request fails which in case we know it will if the user is not authenticated if their credentials are invalid for some reason we know that we threw an error earlier we checked the response was okay the response will not be okay if it comes back as unauthorized which will happen if we use bad credentials so if a bad response comes back from the server then we want to do the opposite instead authenticated to false so now that we've set up the login method in our auth store we need to actually make sure in our composition route here we need to make sure that we provide the auth store with the auth service so what's great about this composition route here this store context is that we only need to declare these services and stores once and then we can share them as singletons across each of our use cases so we'll see that in a bit how we end up sharing multiple services between different stores but for now i'm going to pass in the off service into the auth store and now if we come back into our auth component and we can create an on click listener for our login button and we'll call our auth store dot login and we'll pass in we'll pass in our email and our password so now when the user clicks the login button we're going to call login on the off store we're going to ask the auth service to get a token for us from our back end we'll set it on local storage and then we'll update our observable value here to true so that we are authenticated and then in the auth component we only show the dialog if we're not authenticated so this component will re-render when it detects that is authenticated has changed and we will no longer show the modal so let's go ahead and try this out so make sure you have the back end service running from the beginning of the video and i'm going to use the same login that we have used in postman because if you recall uh we're just using it uh in memory list right now of users with email and password so we're gonna use that for our login here the email will be down at example.com and then it'll be my password for the password and after we click login we can see that the modal has disappeared because our component has re-rendered we can see our login request came back successfully within access token which is great we can now safely say that the user is authenticated so if we go ahead and refresh the page we will notice that uh our our dialog pops back up which is quite strange because we'd expect that we our access token is still in local storage we take a look and we go under application and we look at local storage for http local 3001 we can still see that we already still have an access token being saved so we should not be presenting the modal to the user and the reason why this is happening right now is because when we reload the application we don't call login again so let's go ahead and fix that so i'm going to create a new public method called get access token and what this is going to do is it's going to check local storage so we'll return this return local storage dot get item and we'll look for access token so if if the current value is associated with the given key the access token will return it otherwise it'll return null so in our constructor for the auth store i'm actually going to set this authenticated equal to this dot get access token and we can actually use the double bang here so that is the if the value is non-nullish then this will be coerced into true and if we get no back it'll be still be false so the user is not authenticated so now if we save and go back to our browser we should see that even once we refresh the page we're not presented with the login modal because we still have that token in memory if we were to go ahead and clear that storage and refresh the page we can see we're presented with the login again and then once we log in and our access token is back when we refresh we can see that the modal disappears so i hope you enjoy this short tutorial on how i implement react authentication using mobx if you'd like to see more videos with mobx just let me know in the comments and i will see you in the next video thanks
Info
Channel: Michael Guay
Views: 10,394
Rating: undefined out of 5
Keywords:
Id: kwEpxMqAqkw
Channel Id: undefined
Length: 34min 30sec (2070 seconds)
Published: Wed Oct 20 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.