How to build an eCommerce Website using React Redux, GraphQL, Firebase #9 – Redux Saga

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
welcome to the ninth video in this tutorial series on building an e-commerce website using react Redux graph QL and firebase now in today's video we're going to be looking at redux saga well Redux saga is an alternative to using something like thunk middleware because it allows you to handle the asynchronous code within your react Redux ecosystem now typically a Redux action creator is just a function returns an object with typically a type and a payload that will eventually be used to update your Redux store now func middleware allows you to write asynchronous actions so you can basically fetch data from an API within your action before you actually update your Redux store now what Redux saga does is it allows you to take all of that asynchronous code out of your action creators and it will actually intercept actions that you tell it to it will call a generator function that can handle those asynchronous events and then it will dispatch another action to actually go ahead and update your Redux store before we get started I just want to ask you guys to subscribe to my YouTube channel you can find it at youtube-dot-com forward-slash simple touch but I also want to ask you guys to check out the playlist that I'm creating for this series so I'm gonna be posting a link to all of these pages in the description of this video but I'm as I'm creating these videos I'm adding all of them to this playlist of course I also want to let you guys know that there is an official repository for this project at the end of each of these videos I'm creating PRS I'm merging my code with master so you guys can come here you can check out the code that I'm writing maybe you just want to clone the project but again I'd like to ask you guys to star fork the project of course I also want to let you guys know our official web site that's simple to calm but of course the most important thing is please do subscribe like and on my videos I do read your comments and they do guide me in the content that I produce going forward before we can use saga middleware in our application we need to install it and pass it to our store to do that all we need to do is head over to our terminal and install the library so I'm going to do MPM install redux saga hit return and its gonna install the dependency once that's installed I'm just gonna restart the application so NPM runs start okay so the first thing that we need to do is actually pass the redux saga middleware to our Redux store so that we can use it in our application to do that I'm gonna go into my create store file which is in the source directory redux create store j/s and we need to first of all import redux saga itself the name I'm gonna assign it is gonna be create saga middleware and I'll explain why in just a second so we're gonna call it import that from redux saga and we need to first of all create an instance of the saga middleware before we can pass it into our middlewares array so to do that I'm going to create a Const called saga middleware and all it's going to equal is this creates agha middleware but we're gonna call that as a function will then be able to pass that into our middlewares array which will eventually be passed into our apply middleware function which is used in our create store function when we create our store on runtime now just after where we call create store and it's very important that this comes after where we make that call we need to then call a method on our saga middleware which eventually we're going to use and pass our route saga into now currently we don't have any sagas we also don't have a route saga but the way that this will work is very similar to how we currently how we currently have our route reducer so we use our route reducer to to combine all of our reducers and we're going to do the same thing with our sagas so within the Redux folder I'm gonna create a new file called route saga j/s and at the top of this file we're going to import some effects from the redux saga library so we're gonna say Redux all get slash effects and the two effects we're going to import are going to be the all effect and cool okay so the difference between these two is that all allows us to resolve effects in parallel similar to promise old and cool allows us to cool functions okay so now we need to create our first generator function to do that we're going to say exports default and we're going to create our first generator function to do that use the function keyword followed by an Asterix followed by the name of this function which is going to be route saga then we'll be able to use the yield keyword followed by all which will allow us to pass it an array where we can eventually pass it our sagas now of course at the moment we don't have any sagas to pass in here so I'm not gonna do that I'm gonna come back to this a little bit later but we're gonna come back over now to our create store function because that is enough for us to actually import and pass into our run method so at this point I'm gonna just import my route saga I'm gonna do that after my route reducer it actually doesn't matter where I import this but for me this just makes more sense and I'm just gonna pull this of course from the file I just created which is my route saga George is and will simply pass that into our run method ok so the first component that we're going to be refactoring is our sign-in component so let's go ahead and make a start now to do that I'm going to head over to my text editor and the first file that we need to look at is in our user folder within redux and it's our user actions and our user types okay so what we're going to do is we're just going to create some space at the top of our actions file because we need to create two new actions but before I do that I need to create a new type which I'm going to explain more about as we move through the tutorial but for now let's just create the type we need which is going to be email sign-in start and the value here is going to be the name of the key and we're also going to move the sign-in success to the top so what I'm doing here is we're going to be doing a lot of refactoring here we may you know use some of these we may not we may create new ones but the ones at the top here are the ones we're gonna be using at least you know right now let's go back over into our actions file and we want to use those two types now so we need to create two new actions so we're gonna export cons the first one is going to be email sign-in start it's gonna take the user credentials and it's just going to return an object because it's just a simple action now which is gonna have a type which is going to be user types which we're importing above already dot email sign-in start and the payload here is going to be the user credentials the next action we need to create is just going to be a success action so it's just gonna be sign-in success and again that's just gonna take the user here and return in action so this one is just going to have type of user types dot sign-in success with a payload of the user that's returned from the firebase old library now you might be wondering why I've included this start keyword here well it's a naming convention used within redux saga and to understand why you'd have to understand how Redux saga works but I'm gonna I'd rather show you then try to explain it I think it would be a little bit boring if I just end up talking too much in this in this tutorial I'd rather do more coding so within the user folder here within redux and creating a new full a new file called user sagas I think it's clear already what what this file will contain is our user sagas and this is what we're going to import into our route saga but before we can actually create any any of our generator functions we need to import a few things so the first is going to be our user types which will import from our types file so we have user types here we need some things from redux saga itself so we'll import from redux saga effects and we need a few effects so we need take latest which I'll talk about in a second we need coal and all you guys already know about that and we need put so take lightest is actually I'll explain that in just a second the other thing we need to do here is we need to import one of our actions which is going to be our sign-in success action here so we're now ready to write our first generator function so what we'll do is we'll just say export function with and the way you do that is just say function with an asterisk after the function keyword that creates a generator function and we need to give it a name I'm going to call it on email sign-in start and we're gonna just yield take latest which expects two things the first is the action that we're listening for to specify that will just say user types which we're importing up here and the name of the the type that we're going to be listening for which is email sign in stock and the second thing that it expects is the name of a generator function that will handle this event when it is cold and it does intercept this action and we're gonna call that email sign in we haven't created that yet so let's go ahead and create that above we'll do that by saying export function to generate your function it will say email sign in and this is going to actually receive the entire action but we don't need all of the contents of it all we need is the payload so we'll see structure the payload from the action and from the payload we're going to D structure the users email and password which is what we're going to use to sign them in okay now although we've written our first saga and yes we haven't written any code within our within this function to handle the event but we will but the Redux store hasn't been provided our sagas so to do that we need to export it first so I'm gonna say export default here and I'm just gonna export this as it will be another generator function but it's gonna be called my user sagas and all we do here is we'll say yield and we say all which accepts an array where we will call the are sagas so the only saga here we need to pass is our on email sign in start because once this is cold it will it will actually call the email sign in for us so we don't need to pass both we only need to pass in this generator function but we need to then import this into our route reducer so within my route with you sorry not my route producer my route saga so within my route saga file I'm gonna import that user sagas from the file I created which is in the user folder user sagas and then I can then use coal here and pass my user sagas and of course as you guys know we have our route saga which is imported in create store and that is passed to this run method here which is where we pass our sagas to our redox store and now we're ready to actually handle signing in the user right now currently if we look at our component which is our sign-in component here we have our form which when submitted calls this handle submit function which dispatches our sign-in action right now of course we don't want to use this action anymore but we do want to take the contents of the action which is this try-catch and I'm gonna move that logic into my Redux saga now of course this isn't going to work in this way we'll have to refactor it but before I do that I'm going to come back over to my sign-in component and rather than importing this sign-in user action gonna import my email sign-in start action which is what I'm going to dispatch here with the users credentials which is the email and password so if we look at this action here again it just takes the user credentials and passes it in the payload of the action object the action object which is then intercepted by my Redux saga which is listening for this action which then calls my email sign in generator function where will the structure of the email and password we then enter the try-catch right and what we want to do here is actually think about just going through these lines and slowly refactoring them so rather than this await keyword we just say we want to yield this we are not importing this earth library right so if I just come over to the actions I know I'm going to need all of these so I'm gonna import all of these from my firebase utility file now if you're not familiar with that then what this is is this is my firebase utility file we created this in one of the first videos of this tutorial series and in this file we have a few helper functions we also just import/export certain things from our firebase both library including auth and this is you know just things that we can use throughout the application to make things easier so I'm just going to import that into the file because of course here where we're using it so we need to import it and finally on this line we are dispatching a success event and this is just it's not going to it's not going to work right we can't dispatch an action in this way from our from our redux saga so the way we do that is we use this put effect so we'll just say yield put will call that and pass it our sign in success action but before we actually go any further with that I'm gonna comment this line out because we're not actually going to to be using it right just yet so I'm gonna delete this code here and we're pretty much ready at this point to test this out in the browser all right so it's not gonna be working a hundred percent but we're at a point where we can kind of test this so I'm gonna go to the browser this is my login page and I'm gonna sign in to a test account so just cuz a joke logs which is a test account I have set up previously at outlook and this is the password let's in so you can see we're signed into the application we're not redirected we need to dispatch that success event to actually redirects us but we are signed into the application you can see the header here is updated I can go to my account page and go back to the home page but we do have a problem and to explain that problem gonna come back to the browser and what I want to talk to you about is what we're doing on this line here right so on this line we are not actually updating the redux tour we're signing the user in but we're not updating the redox tour with the user information which would sign them into our application ultimately right so how is that happening well to answer the question we need to look at app j/s and what we're doing inside of this reactor which is the user fact hook here so use effect works in the same way as component did mount and also what this returns is gonna work the same way as component we'll unmount we unsubscribe here but what we're doing here is we're subscribing using an event listener and this again runs whenever this our application is whenever this components mounted when we initially run our application when the user visits our website we create an event listener and we subscribe to the firebase oath library to determine whether the user is signed in to our application or not and this is where we actually dispatch an action to update our Redux store now the problem is if we were to comment this code out here return to the browser you'll see that it doesn't show we're signed in to our application anymore right so if I come back over to my text editor the problem with this with doing this in this way is that reacts really doesn't play well with dumb events such as event listeners and things like that now sometimes within react it's required for things like scroll events or things like that but in this case we need to refactor this code to handle this [Music] within the redox saga library and this is again one of the benefits of using redux saga it will help us persist the users or status throughout our application right so what I'm going to do is I'm going to take the contents of this use effects hook I'm gonna cut that out and we'll return to clean up this component a bit later but I'm gonna move that code inside of my user saga and I'm actually going to create a helper generator function yes you can do that and I'm going to create that just at the top of the file and the reason I'm not gonna just put this code in to this function here is because I already know I need this for some of my other sagas so I'm gonna create this as a helper function that other functions can use and I'm just going to say that this is get snapshot from user both and what we're gonna do is we're just going to we're just going to create a try-catch here and we'll catch an error which we can log out so console log the error will comment that out for now and I'm just going to paste this code in here so currently this this line here let's remove this pot here but what we're doing is we're effectively subscribing to the user's old status whenever the user's all set as changes within our application so if they're signed signed in there also this has changed they're now signed in it reruns this block of code that's what it was doing before and what it actually gets from the firebase library is this user auth object well the way that we can get this is when we actually sign the user in here within our email sign-in generator function here we can actually get this D structure this off of the response it returns and this will be returned as the user so what we can actually do here is just yield and we can call this get snapshot from user auth helper function that we have created and just pass it the user okay and when we do that we can receive it here we no longer need to worry about user oath because we are now getting it so we can get rid of that and we can get rid of the if statement we also don't need this dispatch here and this closing closing function here we can get rid of that too so we already have the user but what is this handle user profile function what is what is this so to understand that we need to look at what that is so this is coming from our firebase utility file so let's head over to that file and look at that function so again this is a helper function we created in a one of the first videos of this series and this basically just checks if the user that has signed in is stored in our users collection on our firebase database and if they're not so you can see here if they don't exist it basically sets them it adds them to our firebase our far base our firebase collection our database of our users so it basically registers them the only difference in change we'll have to make here is this will now be sent as an object right and I'll explain why that is in just a second so we'll need to make that small change but the other thing to note here is that after it has signed them it has registered the user it will return the user ref and this is what we actually use to update the redux store with the you information because this object contains things like the users display name and things like that which we use in our application so let's return to the file here and the problem is again we can't use this a weight keyword this is a generator function so we say yield but we also cannot call a function in this way right so what we need to do is rather than that we use in effect from a redux saga we call it like this so we first of all we pass the function we want to call which is this handle user profile and the second thing we're going to do is pass it an object and the object will just contain what this function expects to receive so again if we look at this it expects the user auth and any additional data we want to pass we don't want to pass any additional data in this case but what we do want to pass is the user off and we're gonna pass it the user that we get back here when we sign them in and that's all we need to do for this line but then what we want to do is effectively handle storing that updating our Redux store with the users information to do that we need to actually get the snapshot from of this user so to do that we'll just create a constant called snapshot which will yield the user ref which we again get back from this handle user profile function and then we'll just call get on that and that will return the snapshot that we require so we again can get rid of this line here and all that now remains is to dispatch our success event which is our success action here so we're not going to use this set current user anymore we want to dispatch our success event so to do that all we need to do is again move the code we wrote here which dispatches the success event we want to move that out and we want to add it here uncomment it and all this will expect is an object with this information that we were previously passing to set current user and again we can now delete this line here and again this shouldn't have a semicolon we can add that here now although we are currently dispatching this sign in success event here within our generator function which would sign the user in and update the Redux store our reducer is not set up to handle this case right so if we look at this action it dispatches the sign in success type now if we look at our user reducer we have quite a lot of code in here but none of it is set up to handle the changes that we've made so what we're gonna do is we're gonna do a major refactor which is going to be more deleting than anything else and all we're gonna do currently is just delete the initial State all apart from the current user and we're going to delete all the cases off of our switch function apart from the default case we want to define a new case which will be based off of user types dot the success user types dot sign-in success which will return an object with the state and we're going to set the current user to be the action dot payload right that's all you need to do once you've done that you can save those changes and well we can come back over to the browser at this point and we can sign into the application so we'll say Joe Bloggs at outlook which is again the test account enter the password and click login and we'll be signed in to the application but you'll notice we not redirected we were signed in our header updated but we weren't redirected so if we come back over to the code and figure out why well the reason is in our actual sign-in component we are getting the sign-in success value from the Redux store and using that in our use effect hook here right which of course doesn't exist we removed that so now what we're gonna do is in our map state function we're going to map the current user and we'll say user dot current user we are going to D structure that from our Redux store and we'll use that in our use effect took to determine when we should redirect the user to the home page when the users signed in we also don't need to dispatch this so now let's save that and come back over to the browser and what we'll do here is we'll just sign in again and see what happens so we'll say Joe Bloggs @e outlook they'll come and we'll enter the password as usual log in and you'll see now that the header is updated I'm redirected to the home page as I was before and that's fine now there's one last thing we need to cover and that's if I do a reload of this page and if I do that you'll see that I'm kind of signed out I'm actually still logged in right but in actuality the website and application doesn't reflect the fact that I am still logged in even though I know I didn't log out the session is still there so as you guys know earlier in this tutorial we removed the code that runs in this use effect hook that will check the users or status whenever this component mounts whenever we basically run our application and because of that whenever the user goes away from the website and returns to our website or whenever they reload a page in their web browser we are unable to persist the users current session so what we actually need to do is although we can't do it the way we did before we need to find a way to persist the users or status within this application and the way we're going to do that is we're going to create another action which we're going to do in our user actions file we'll say export Const and we're just going to call this check user session which is just going to return a function with a type which we haven't defined yet so we're going to create another type which is just going to be check user session and again the value will be the same as the name of the key like that so in our user action here the type will be user types don't check user session and then we need to create the equivalent saga so let's come over to our user sagas I'm just going to collapse these two functions here so we have a bit more we can see things a little bit easier and we're just going to say export function so generate a function so we need remember the asterisks here I will just say on check user session and we'll just yield take latest and we'll pass it the action we're listening for which is user types doc check user session and then we need to pass it the generator function that will handle this check and we're gonna cool that is user authenticated so we'll say export here again function is user or authenticated and we're going to write that code out in a second but we need to pass this first of all as the second argument here as that's what take latest expects and then what we need to do is very similar to what we do here when we sign in the user alright so what we need to do is we need a way of finding out if the user is currently signed in to our application and in actuality there really isn't a good way of doing that without using that same on earth state changed method that we were previously using from the firebase oath library itself but we're going to interact with that a little bit differently so actually what we need to do is we need to come over to our firebase utility file and we need to create another helper function right and what we're going to call that this function here so we'll just say export Const and it's gonna be get current user because we're going to use this to find out if the current user is signed into our application or not now to do this without an event listener we're gonna have to resolve a promise so to do that this function is just going to return a new promise so we'll need to pass in the resolve and reject and then we're going to basically create unsubscribe which will equal our oath library uh north state changed which is going to receive the user auth object which could be null if the user is not signed in and then we're going to unsubscribe here by just calling this function because if you remember from earlier videos when I've talked about this on earth state changed method it returns a function which we can use to unsubscribe and that's how we're going to unsubscribe here too and then we can immediately resolve the promise once we have the value of user oath that tells us if the user is signed into our application or not and just as a fullback we can also reject here okay so that looks good and what we're gonna do now is come back over to our users saga specifically our is user authenticated generator function and we're gonna use it here so up here where we import u helper functions from our firebase utils file I'm going to import that get current user helper function I just created and within my is his user authenticated generator function what we're gonna do here is we're gonna have another try/catch so we'll have a try-catch here we'll catch any errors we'll lock them out if we have them but we'll do that when we're debugging so for now I'll just comment that out and the first thing we want to do is we want to get back that user auth object right which again is here so this is get current user and it returns that user auth object so what we want to do here is we want to get that user also with a Const user auth equal also yield and we'll just cool get current user here now if the user doesn't exist so user oath here is null right then we'll just immediately return out of this function because we don't want to do anything else the user is not signed into our application because again if we look at that helper function what we're doing is we're creating a promise we're subscribing to on offset has changed on earth state changed method from our host library from firebase which returns the users also object and this will return null if the user is not signed into the application in which case we don't need to go any further however if they are signed into our application then we want to restore our redux our redox tour with the current users information which is exactly what we're doing here right with our get snapshot from user auth helper function that we created so again all we need to do here in this case if we get past this check is we need to yield get snapshot from user off and just pass it user off okay so now that we've created our on check user session saga we simply need to export it with our user sagas so that we can intercept that action will do that by passing it to this array here of our user sagas so I'll say comma all so I'll say comma call and pass it my uncheck user session and again we only need to pass in this uncheck user session saga because this is where we define what we should the action we should be listening for and this will call is user authenticated for us so we only need to pass in the single saga but that's not all we need to do because we're not actually dispatching this event from app J s just yet so let's come back over to app j s let's uncomment out this user fact hook we don't need to worry about returning anything here we also still don't need any dependency we do need to import our action here though so we want to import check user session and this is what we actually want to dispatch so we'll just go ahead and dispatch that here when we mount and then just as a nice clean up here let's just delete everything that we are not using so we don't need redirect and we don't need to use selector anymore either so that's all we need we can just save those changes let's just quickly review the file so it's a much simpler file now as well which is really nice and that's all so now we're doing it we can come back over to the browser okay and now we're ready to actually test this out in the browser so I'm going to go ahead and log in to one of my test accounts so it's Jo logs ads outlook.com sign in with my password and sign in as you can see I'm signed in to the application can move around the site normally and I can refresh the browser as you can see I'm still logged into the application so I'm now persisting the users or status successfully but I want to talk to you about something that is not working and that's how we are currently logging out of the application so if I click on log out you'll see that nothing happens because I'm not actually look I'm I'm logged out of the application in the background but I'm not updating the reduxid store so if I was to reload the browser you'll see that this session is cleared because I'm no longer able to obviously access III don't have the session so it's not able to persist it but of course that shouldn't happen it should immediately look these are out and update the redux or so the first thing that we need to do is come over to types and create our first our types so this is going to be sign-out user start again that takes the value of the name of the key and then secondly it will be a sign out user success and again that will take the same value as the name of the key we then need to come over to our actions over here we need to create our action so we'll say export Kant's sign how user start equals function just going to return an object with a type which is going to equal the user types the sign out user start and then we need to create another action which is Const sign out user success right and this is where we will use this to update the redux store once the user is signed out of our application using the firebase oath library itself and this is just gonna have a type with user types the sign out user success so we now need to create our new sagas that will actually successfully sign out the the user so up here at the top when we import our actions we need to import another action which is going to be sign out user success and then we need to create our sagas that will handle signing out the user so the first one we'll create will just say export function to generate a function so don't forget the asterisks and we'll just say on sign how user start and this will just yield take latest we will pass it the action we want to intercept so user user types dot sign sign out user start and then we pass it the generator function that will handle that so we'll say export function the generator function and we'll just call this sign how user we will write this in a second but we just need to pause this here and then finally we also want to export this from with our user sagas so here I'm going to call and pass our on sign out user start and this is again how we will intercept that event when it is dispatched so how do we sign out the user so let's look at how we're doing it currently to do that we need to come over to our header and in our header JS file we have our sign out button and at the moment it's very simple we just call off sign out right so that's it's pretty simple so if I come back over to my saga in my sign out user generator function I'm gonna have a try-catch we're gonna catch the errors and will log out the error if there is one but by default we will will not love that will comment it out for now and then all we want to do is yield both dot sign out right because that's what we were doing in our header J's file it's just or sign out like that and then what we want to do is update the the store so we're going to call our sign out user success and we're going to dispatch that action to do that we just say put well let's say yield first so yield put and then we call sign out user success and we don't need to pass it anything that's just gonna go ahead and update our Redux store now to do that we need to come over now to our reducer which will update the store and what we want to do is we want to create a new case which is going to be user types duct sign out user success but we will return a new object with the state we're going to pass it our initial state which is going to set the current user to null and sign them out of our application so what that means is when we come over here all we need to do now is in our header rather than calling earth sign out directly we need to dispatch the action itself so to do that we need to import from Rida react Redux use dispatch and at the top of the file we need access to dispatch so I'm gonna say Const dispatch equals use dispatch that gives us access to it up here we need to create a Const which will be sign out right just gonna be a simple function here and all we gonna do here is we're just going to dispatch our action so we'll say dispatch here we need to import our action we don't have it yet so here we're gonna say import from our actions so we'll say it's in our in redux user user actions and it's something like sign out users start right so we just need to dispatch this action here and then all we need to do is just cool this when the user clicks on sign out so currently it happens when the user clicks sign up they go directly with auth sign out now we'll just call well what do we call this it was its just sign out so now we'll just call this a function to dispatch the action that signs out the user that also means that we don't need to import Earth into this file anymore because that's handled that's decoupled away from that that logic is now decoupled from this component okay so let's now come back over to the browser and let's sign in again so I'm just going to sign in to sign in to that same test account so Joe Bloggs at outlook.com sign in with the password I'm signed in I'm redirected and go to my account and now I can actually click on logout and I'm logged out of the application I can reload the page I'm still logged out so that's fantastic so far in this tutorial we've managed to refactor a significant portion of our code to work with redux saga that includes the logout functionality the sign out functionality and also the ability to persist a user's or status and all of that is now being taken care of for us by redux saga which is fantastic and a lot of the foundation has been laid for us to actually continue refactoring this application to actually work with redux saga in regards to the flows that remain for us to look at which includes registration and email password so let's just go ahead dive right in and refactor those the first one I'm going to do is the registration float okay so the first thing that we need to do is create our new action and types so the only type that we need to create for this flow is going to be sign user start right it's going to take the same value as the name of the key like that let's come back over to our user actions and create our action so in actuality this is actually gonna be very simple it's just going to require exports Const sign up user start again it's going to take the user credentials and then it's going to simply return an actually a function that returns in action with an object sorry with a type which is user types the sign up users start with a payload of the user credentials right so now we're ready to go ahead and grab create sorry create our Redux saga so to do that what we're going to need to do is just go ahead and enter here create our our first saga for sign up so we'll say export function which is a generator function I will just say on sign up user start and we'll just say take latest we'll pass it the the action that we're going to be intercepting and listening for which is going to be sign up user start and then we'll take what we'll pass in the generator function that will handle that so in this case it's just going to be export function which is a generator function sign up user and we're gonna return to this in just a second but we need to pass that in here and also of course we also need to pass it to where we export our sagas so this is becoming quite a long line here so I'm just gonna move this on two separate lines so it's a little easier for us to to see and and work with so here I'll just say call and I'm gonna add my own sign up user start saga so will now be listening to that listening for that within our redox tour whenever this action is dispatched we'll intercept it we'll call this generator function that will handle signing up the user now again this is going to receive the entire action which means we can D structure of the payload and will then be able to D structure things like the the credentials that we need which is going to include the display name the email password and the confirmation password and then what we can do is we can actually save ourselves a little bit of time by coming over to the user actions and let's look for the previous action that we were using to sign up the user which is right here right so sign up user and let's just take the entire contents of this action cut it and let's come back over to our saga and paste that in and I'm going to go through the lines and we're gonna we're gonna refactor this so that it will work within our Redux saga so some of this is still the same as you can see we have this password error here which basically checks that the password matches the confirmation password and allows us to to render an error if they don't match so again here we are dispatching another event which is an error event and here we actually need to think about how we're going to handle this because we don't actually currently have a errors errors action that we can dispatch so we're going to comment this out for now and I'm going to come back over to my user types and I'm going to create a new action which is going to be called user error right again it's going to take the same value as the name of the key we're going to come over to our action which is right here and at the top of the file here under sign up users start I'm going to export Const user error and that's going to take in error and return an object cool function that returns an object with a type of user types dot user error and a payload of the error okay and what will then do is on our reducer we're going to have a new piece of state which is going to be user errors which by default is just going to be an empty array will then add a new case to the reducer here so we'll say case user types dot user error and we will return the state but we will set the user error state to be the action payload okay now when the user manages to successfully sign-in we will want to restore this right because they've successfully signed in so the errors no longer exist so what we're going to do here is we're going to set the user error back to an empty array in this case okay so now what we can do is come back over to our saga and where we were previously dispatching this event like this we can come back to the top of the file and import a new action which is going to be user error our user sorry no user oath to our user error action which we created before and all that does is it expects an error so here what we're going to do and actually also just notice I was expecting confirmation password exactly just confirm password and what we want to do here is we're going to say yield put and we are going to dispatch that directly so we'll just a user error and we're just going to pass in here and we're just gonna pass in the error here so we can then remove that and we can remove this return and finally we just need to refactor the code within our try catch that actually handles signing up the user there's not much that we need to change here we just need to change this awake keyword to yield we still want to return the destructor the user off of the response object but then what we're going to do is we're gonna say yield rather than this awake keyword here and remember we can't call this handle user profile the same way as we did before we need to call it with the Col effect we can then pass in handle use handle user profile but we call it by passing in the function we want to call and then we need to pass it this data as an object these are what we passed to the handle user profile function but we need to pass the user as the user auth and we need to pass the display name as an object to additional data which again if we check this it expects this additional data object if there is one if there is any sorry so that's going to be an object there we don't need this closing bracket here and finally we don't need to dispatch any thing here at all and that's actually all we need to do to refactor the asynchronous code for signing up the user the only difference now is actually going to be on the component level so let's come back over to our registration component so we have our signup component in index and we have this a few things here so currently we're looking at signup success we want to switch that to look for current user so when we map our state here we want to map two things okay so the first thing we want to look for is going to be the current user which we can get off of user current user and then the second if I just check the reducer what we're checking for is the user error array so what we'll do is we'll come to again our signup component and we will get that from our user state and again we want to get both of those from our Redux store here so we'll get the current user and the user error array and the first thing we'll do is on this use effect hook we're checking if the user has successfully signed up if they are we're redirecting them away we are now using the current user object directly to do that so we'll pass that in as the did as the dependency for rerunning this code and also that will be the condition that needs to match in order to redirect the user we also don't need to dispatch this anymore so we can get rid of that and we can also remove the import for that action we're not using that anymore and also the signup user action we're not using that we're now using the signup user start action so actually within our handle submit function where we were previously firing signup user we're now firing signup users start but again this object of these is credentials remains the same and then finally this is where we handle the actual users errors so where we have this user error array here we want to update the array that we are passing here and that's all the changes that we need to make to this component okay so we're finally ready to test this out in the browser so let's go ahead and do any sign up so I'm just gonna say here example full name example email dot-com enter a password first of all one that does not match so we should get an error okay so I'm not getting so this doesn't seem to be working so let me just check the code ah so on signup users start we forgot to or I forgot the yield keyword here that's very important alright guys so what I actually just did was I realized I made a mistake and as you can see nothing is is happening when I click register which is a little bit deceptive because what's actually happening in the back is I have successfully been signed up I'm just not reflecting that in the application right so if I come over to inspect what you'll see is that if I click on register again I get this error which I'm logging out in the background which says the email address is already used by another account and the reason is that I've clicked this multiple time so if I was to change this email to one two three this doesn't exist right so if I now register you'll see nothing happens I don't get an error but if I click this again I now do get an error which basically says that the email address is now already used by another account right so obviously what that means is that I'm simply not when I'm successfully signing up I'm not redirecting the user and the reason is if I come back over to the code is when I refactor this logic I just reflected this line here which we're using to handle the user profile right here right so what I actually did was I actually created a helper function which was just get snapshot from user oath which will actually handle this for me right so what I'm gonna do is I'm gonna do a little refactor on this and what I want to do is rather than call this directly I'm gonna do the same thing I did with email sign-in which is I passed the user directly to this helper function that will handle this for me so what I'm gonna do is I'm just going to comment this line out for now I'm gonna say yield and what I want to do is I'm gonna say get snapshot from user auth and I'm gonna pass it the user and I'm also gonna pass it the additional data which I'm going to define as a constant above right and I'm gonna pass that in as the second argument to this helper function so I now have this additional data so if I now come back over to my helper function I'm gonna pass this in here I'm going to default the value to an empty object and I'm gonna pass that in to my helper function now that's really good but there's another thing that's really important that I missed as well which is here when we actually check if the user if the password and confirm password match we also need to make sure that we return here because that will basically put it that means that if this does throw an error will dispatch the action to render the error to the user but we then need to make sure we return immediately out of this function and that we don't proceed to try and and sign up so that's this is a very important line here that you guys need to make sure you add that in and again you know this is a long tutorial so yeah it's it's it is a lot of refactoring going on here so apologies for missing that but you know maybe you guys spotted that and if you if you spotted that before then well done but make sure to add in this return here it's very important okay so let's finally come back over to the browser and let's test this out so let's go to the registration page let's do another full name example at test.com enter a password first of all let's enter a password it does not match so you can see we render the air now let's make sure the passwords match and try and register and I'm also redirected I'm logged in I'm signed up and that's it we've successfully refactored our registration route the next forum and component we need to look at is our email password form and this is the last form that we need to refactor to complete brief add to complete the integration of redox saga into our application so the first thing we need to do is just head over to our text editor and create our types so I'm going to come into the Redux folder user open up my actions file and my types file and let's create our types so the types I need to create off the top of my head initially are going to be reset password start and of course the corresponding success type so reset password success and we're going to assign both of those the values which is going to be the name of the key itself we can then come over to our actions file and just create the corresponding actions okay so let's go ahead and do that so we'll say export Const reset password start and that is going to take the user credentials return a function with a payload the type is just going to be user types dot reset reset passwords start and the payload is going to be the users credentials and the second action we need to create will say export Const reset reset password success we're not gonna pass anything in here but it will be a function that returns an object with a type which is going to be user types dot reset password success and the payload here is going to be true so what we want to do here is now come over to our user sagas file and we need to create our our saga so at the top of this file we need to import the action that we want to dispatch on the success event which is going to be called the reset which is called the reset password success action we just created and if we come down to the bottom of the file this is where I'm going to create my new sagas so we're going to create our first generator function so we'll say export function using the function keyword followed by an asterisks we can create a generator function and we'll say on reset password start right and then we'll say yield take latest it expects two things firstly the type the the type where we're listening for which is going to be reset password start and the second is the name of the generator function that will handle this asynchronous code so we'll have to create that so export function it's the generator function we'll just call this reset password and this is going to receive the entire action so we can D structure off the payload and then we can D structure the email from the payload and what we want to do is then pass reset password' in to take latest because that's the function that will be called when when when it intercepts this this action we can then we then need to make sure that we export this at the bottom of the file so we'll say call on reset password start and then finally we're ready to come over and grab the code from our actions file so if you remember we are refactoring this from what was previously a read it just a simple action so this was our reset action reset password action that we were using before to handle this to handle resetting the user's password and sending the password reset email I'm gonna take the entire contents of this action and I'm gonna paste it into my generator function but this is actually going to require a little bit more refactoring than what we've done previously the reason is that we're using this then and dot catch callback events which we can't do within our generator function so what we can do is we can move this into a helper function so within my user folder I'm gonna create another file called user helpers j/s and I'm going to have to import my o'the library from my utility function my utilities file so let's come back and import so it's firebase slash utils we'll need to import our earth library and then I can create that I can move that code into this so I'm going to just call this I'll say export cons and I'll say handle reset password API right and this is just going to take the users email and what we want to do is we want to return a new promise and obviously this is going to allow us to either resolve or reject and what we need to do is come back over into our saga will we pasted this code we'll cut that and we'll come back over to our helper function and paste that in we can remove the awake keyword and much of this is going to remain the same we also need this Const where we configured the return URL so I'll just paste that above which we're using here we're already getting the user's email but rather than trying to dispatch events in these cases what I'm actually going to do is if we are if this if we are if we enter the success callback I will resolve this promise and if there is an error I'm going to throw the error using reject and once I've done that what I can then do is come back over into my saga we will need to import that helper function from the top of the file so up here we're going to import that from our user helpers file so it's handle reset password API and within our generator function we are simply just going to have our try catch right but what we'll do is we'll say yield coal we'll call our handle reset password API and we'll pass it our email and what yield will do is it that it will allow us to await our promise to resolve so if you remember again our helper function we're returning a promise so it's going to wait for this to either resolve or throw an error now if we throw an error from within our promise then because we have this in a try-catch we can throw the error so we can now we can either dispatch a success event which I'll do here using the put effect so I've already imported that at the top of the file so it's reset password success so I'll just call that here but if I want to throw an error then if we look at our helper function I'm already passing the error here which is an array with a string so all I have to do is again say yield put and I'm going to use this user let's just check what it's cold the user error action right and I'm going to dispatch the user error action and pass the error array that we have quote in the try/catch okay now there's one thing we need to do on our reducer so let's come over to our reducer and we need to create some new initial state which is going to be reset password success by default is going to be false so we'll have another case within our reducer here we will solve case user types dot reset password success and in this case we will simply return an object with the state but we'll change this we reset password' success and this will be changed to the action dot payload and then what we can do is come over to our component our email password component and we'll need to refactor this a little bit so what we actually need to do now is dispatch the new action that we created which is a reset password start action so we'll say reset will import reset password start from our actions file and where we dispatch that so if we look at our form on submit we call handle submit and we dispatch this action so we now need to dispatch a reset password start and we're still going to pass in our email that's the same but what we then need to do is think about how we handle success in our air events so currently we are we are getting two so what we need to do is we need to get the first of all if we look at our reducer the two relevant pieces of state that we need is the reset password success and the user error array right so let's come back over to our component and we need to update our map state function so the two things we need is the reset password success we can get that from the user dot reset password success we also need user error which is going to be from user to user error and then we can get both of those from our Redux store using our use selector hook will be passing our map state function so we can then D structure that so we can get reset password success and the you Raye and then within our use effect hooks we are already listening for changes in the reset password' success state and then we are dispatching this event we don't need to do that right now but what we are going to do is continue to just redirect the user and here we have our use effect took here where we're listening for the errors so rather than listening for reset password errors we're not going to listen for two changes to the user error array and then if that is true then we'll update our errors a local errors array with the contents of our user error array that we're getting back from our Redux store cool so let's save those changes and head back over to the web browser I'm just going to reload this a few times first of all let's enter a random email that does not exist in our our database so I'll just say example at my domain calm and as you can see I'm rendering the same error message to the user and if I enter a valid email so for example Joe Bloggs adds outlook.com and click on email password I'm redirected to the login page and the email would have been sent but what happens if I try and click on reset password well I can't access this but what you will notice is that if I reload the page I can then visit the page I can get get back to the email password page the reason that this is happening is because in my code I have this use effect hook which runs when the component is mounted and it also runs whenever it detects a change in the reset password success state that we're getting from our Redux store and this is what we're using to whenever this code runs we are dispatching this event from our user saga as the success event which in our reducer sets our password are reset password success it's sex it sets it to true right and the problem is that because our state in the Redux store is persisted they're unable every time they try and navigate back to our email password page this code runs and because it is true which is what we're evaluating for they're immediately redirected back to the login page so what we need to do is we need an additional way of resetting our user state our user state whenever they have successfully requested the email password whenever they've requested their password to be reset that will reset the state in our redux tour so that they can access this page again so to do that what I'm going to do is I'm just going to come over to my user actions file and what I'm gonna do is I'm going to create a new action and I'm just going to call this reset user State right it's not going to expect anything it's just going to be a function that returns an object with a type and of course we need to define that type so in my user types file I'm gonna create a new type which is just going to be reset user state again it's just gonna have a string value with the name of the key will then be able to come over to our user actions file it'll say user types dot reset user state right and then what we'll be able to do is in my in my e-mail password component I'm going to import that new action which is reset which is reset [Music] which is reset user state and then we can dispatch that at the same time just before we redirect the user will call dispatch and we will dispatch our reset user State right so we can then save that and now if I come back to my reducer we already have a case where we are restoring the initial state right which will reset all of our state and so what we want to do is we want to stack this right so we'll create an additional case here so we'll see on this case which is user types a dot reset user state and we'll save that and because we've stacked it that's absolutely fine it's not going to be a an issue this is one way of doing it but because we were resetting it I think this should probably come at the very bottom of our reducer like that so I'm just going to move that down to the bottom because this is for sign out and reset we just restore this date so now if I come back to the browser and let's again let's test this so refresh it and let's try so let's enter a valid email so Joe Bloggs at outlook.com email password and now let's try and reset the password again we can access this page without any problems okay so at this point we only have two things left to do one is we need to think about how we can refactor our sign-in with Google to integrate that with redux alga and the second thing that we need to do is we need to figure out how is just go through the application and we're move any of the old code that we have that we're not using anymore right so let's start off with our Google sign-in and this is going to be really easy because we've already done a lot of the groundwork so I'm just gonna go into my text editor and i'm gonna go into again the redox folder the types file and i'm gonna create my my types so the first type i'm gonna create is Google sign-in start and what I want to do is just assign that the same value as the name of the key we'll save it then all we need to do is go over to our actions file and create our action so all this is gonna be is export Const Google sign-in start alright and we're not going to pause anything in here this is just going to be an action that returns an object with a type which is going to be user types dot Google sign-in start there's not going to be any payload and then we need to come over to our user sagas file and we're going to create our saga so we'll just say export it's a generator function and we'll say on Google sign-in start and we will yield take latest user types Google sign-in start we need to pass that the generator function that is going to handle this event the asynchronous code so we'll say export function Google sign-in again we don't need to pass anything in it's going to receive the entire action that actually doesn't have a payload so we don't need to worry about that we're gonna pass that into our take latest effect and then we can remember to export this with the other sagas in the file okay so we're now ready to copy in the code from our previous action so let's come down and find that so this is our Google sign in this is our try-catch we're just going to take this code and put that into our Saga now it's pretty simple what we have to do here so rather than awaiting this our off sign in with pop up what we're gonna do is we're gonna D structure from there response the user we can then remove all of this code here and also we need to remember here that we need to add a yield keyword here which is going to mean that we wait for this to this promise to resolve basically then what we can do is the same thing that we did with our sign-in so let's come up here and look at our sign-in saga so we have where is that set the very top of the file email sign-in we created a helper function which was get snapshot from user auth so I'm just gonna take this code come back down here and paste this line in so we're getting the user back we're passing that in that's the user ortho object and again let's just remind ourselves what we're doing so this this function is at the top of the file and all it does is it just takes that user and it just basically uses our utility function to sign the user in and update our Redux store so let's come back over to the so what we need to do is make sure we're dispatching that the right action from our component so what we need to do is come back over to our component and our sign-in component and as you can see here we're dispatching our sign-in with Google here so what we need to do is rather than import that from our actions file we can remove both of these and we're just going to import our then below the name of the action which is we just need to import Google sign-in start we'll import that action and then in our handle Google sign-in function here where we dispatch this will update that to cool the correct action which we can then save and then what we need to do is just come back over to the browser and test it out so let's refresh this a couple of times click on sign-in with Google we're gonna get our pop up I'm gonna select my account and I am logged into the application I can view my account as normal and I can log out just the same right so that's working it's really easy to do now the reason that was so easy is because we've already written the code for this earlier in this tutorial it's very very similar to our sign-in logic we already created the helper functions that meant we can share the code between these two events and they work exactly the same way so we don't need to worry about that at all okay so at this point all I need to do is just go through and clean up the code so what I'm gonna do first of all is come over to my user folder and go into my actions folder and we're not using any of these imports here at the top of the file so I'm going to remove those we're gonna come down these are all of our old actions the remnants is of our older actions that we're not using anymore so I'm going to delete all of those just make sure you don't delete any of the ones we've written in this tutorial let's save it let's just go through the files one by one so this is our reducer I think everything in here looks good is our user sagas file yep this is all good our types we can remove all of these old types that we're not using anymore that actually feels really good to delete those so that's great let's also just come over to our components and let's just check those one by one so we're not importing anything that we don't want to use that looks good our sign-in component and I'm just checking that we're not importing anything that we're not using anymore and yeah everything looks pretty good right now as a bit of bonus content to this tutorial what I want to do is leave you with a parting gift which is just a really really small refactor to our components around how we're currently redirecting the user on success events so this affects the following components it affects our sign up component our sign-in component and our email password component so currently what we're doing is within this use effect hook we're checking for whenever a the success event occurs so whenever they successfully reset their password what we're doing is we're accessing the history from props and we're pushing them to the login route we're doing the same thing on sign in and sign up to but it's basically the way that we're currently getting access to history if we actually look at how we're doing this what we're doing is we're importing with router from react router dome and then where we export our component which is email password in this case we're wrapping it with with router and that's how we gain access to history within the props of our component however this is the old way of doing this if as if you are working with a stateful component class-based component and obviously now we are using react hooks so we're gonna do this differently so what I want to do is rather than using with router and what I'm gonna do is I'm just going to simply export my component but to gain access to history where we previously imported with router from react browser dome I'm now going to import use history which is a hook from react browser dome which works very nicely with reacts hooks and to access that all I need to do at the top of my function of my component I'm going to create a course called history which is going to equal use history which I need to cause a function and I'm actually going to move up my dispatch where I define dispatch here and then all I have to do is what I want to redirect the user I'll just simply say history that push so we can get rid of props and that's all you need to do to use the use history hook so we need to replicate that change in our sign in and sign up so where I was previously importing with router I'll now import use history we can get rid of the props keyword here we're not using it we can come down here and just remove with router we're not using that anymore cool let's do the same thing on our signup components so rather than with router it's now use history and we want to as well we'll need to remember to create that instance so we'll say Const history equals use history call that as a function and in here we'll say Const history equals use history call that as a function remove the props keyword here let's come down and remove with router and that's all you need to do we're now using the u s-- history hook instead of with router and let's test that on the browser as well so i'm going to come over here and just use one of the forms so let's use our login component look into a test account so joe plugs e outlook.com and sign in and as you can see I'm still redirected just as I was before but we're now using the use history hook and that brings us to the end of this video tutorial where I just want to remind you guys that at the end of each of these videos I am going through I am creating PRS and I am merging with my my code with master so again if you guys want to check out the code that I'm writing in these tutorials I encourage you guys to check out the official repository for this project you can find a link to that either in the description of this video or you can visit my github page which is github.com forward slash simple Tut and you can actually look at the code that I've written you can compare the code but of course I also just want to congratulate you for making it to the end of this tutorial it definitely was probably the most difficult tutorial that we've done so far in this series so really congratulations to you for making it this far and also thank you for supporting this series and watching it but that is it for this tutorial so again thank you and I look forward to catching you again in the next episode
Info
Channel: SimpleTut
Views: 9,035
Rating: undefined out of 5
Keywords: ecommerce, react, react redux, GraphQL, React Context API, Node, Node JS, redux, online store, stripe, stripe api, shopping card, paypal, firebase, react router, react router dom, routes, routing, Google Sign-In, Google Auth, Google Sign In Authentication, login, signin, react hooks, useEffect, useSelector, useDispatch, redux hooks, useState, redux saga, useHistory, saga, redux saga middleware, generator function
Id: su9XgeW7g-Y
Channel Id: undefined
Length: 100min 26sec (6026 seconds)
Published: Sun Jun 07 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.