Learn React #13 - Introduction to Redux Saga and getting data from APIs

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey everyone in this video we're gonna go over how redux saga works how we can connect it with our existing redox application and how we can make api calls and store that api data in our redux store using redux saga now if you watched my previous videos you know that i've sort of been alluding to redux saga quite a bit in the past and anytime we call an api i always say that this is one of the proper ways to do it and i still stand by that and i think redux saga while it can be a bit daunting at first can be one of the best tools you could possibly learn when it comes to the react and redux toolkit so before i get started i just want to say thank you all for your support on this series i couldn't be happier with the amount of responses i've received from you guys and all the feedback um and i just gotta say thank you so much and i'm really excited to keep pumping these videos out um and yeah if you find value in this video please consider liking leaving a comment subscribing it really helps with the youtube algorithm to get these videos out there so without any further ado let's just jump straight in so in this example essentially what we are going to do is going to be just calling a uh api with our redux saga and storing the value the response that we get back from that api inside of one of our reducers and if you're not familiar with how to set up react and stuff like that or what a reducer is make sure you check out my previous video which is all about um redux and how to set it up because we are going to actually be building on that code and what i want to say is if you read the redux saga documentation you'll see that it's actually quite um concise and it's not the easiest to understand they sort of put everything into one file but i want to help break that down for you so that not only will it be more clean when you code it yourself and a bit more scalable but easier to understand as well so as you can see from this diagram that i have here pretty much this is how redux saga will work with redux first of all inside of your component whenever you want to do something you will dispatch a redux action this is just going to be a regular redux action just like the ones that we coded in the last video the only difference is when you dispatch that redux action instead of having a reducer in the actual redux store that will handle that action and sort of catch it like we did before with the increment and decrement for our counters instead we will have something called a watcher saga and that watcher saga will watch for any redux actions that are dispatched and map it to its own redux saga functions so pretty much the reason redux works so well with other libraries is because whenever you dispatch an action in react you're not only sort of um you're not only dispatching it for redux but all the things that connect with redux can also use it such as redux saga and once redux saga catches that action it will pretty much map it using this thing called the watcher saga to the appropriate handler function that will actually make the api request and that handler function will then dispatch another redux action that will store the data back in our redux store so to give this a proper example what we're going to be doing in today's example is a very simple api request that's just going to get the information for a user so our component is going to dispatch for example a get user function a read um action that action will then hit the watcher saga the watcher sagger will then call something called for example handle get user that handler function will then call a request function called like let's say for example do get user or let's say like request get user which will actually make the axios api call and if you remember from my other videos let me zoom in a bit here you can see here that before for example when we wanted to hit an api we would be using a use effect inside of the actual component that would get the uh that would use axios to call the api but instead axios is going to be calling the api from a request function in a request file that we have once that request function gets the data it's going to return it back to the handler function and that handler function is pretty much just going to dispatch something that's going to be like you know set user that will set the user object in our redux store that will allow us to access that user function anywhere in our react application no matter what component it is and that's really the difference between using an api request in just a component with a use effect and using it with redux sagas it allows you to streamline the process it allows it to asynchronously happen without blocking the component or having anything else within the actual component dependent on it and it'll allow you to more easily sort of structure your api calls assuming that you're making a full-on application now if you don't understand this entire flow just yet don't worry it looks a lot more complicated because i use a lot of different colors and stuff like that but we will be going step by step and it will be a lot easier for you to understand once we actually get into the entire application and the entire code now the first thing we have to do is we have to set up our endpoint and in the next video i'm going to be showing you how to do that with express but for this video we're going to be using the same tool we used for one of our previous videos called jsonplaceholder.typeeco.com and i love this because it's pretty much just a website with a bunch of fake data that you can hit now they already have a user's endpoint but that's going to return an array of users and i want to return a single user as if you're authenticating now what i'm going to show you how to do is how to create your own fake data so if you want to try this out on your own you'd be able to do that so scroll once you're on the website and i'll have the link of this in the description scroll down to the bottom where it says use your own data and i'll zoom in a bit and then click the link in the description now over here it'll pretty much say that all you have to do in order to create your own server with your own data is first just go to the uh repo so whoops go to this repo so github.com type ecoslash demo i'll have a link for this as well fork the repository so you can go ahead and fork the repository and then once you fork the repository to your github you can click the db.json and you can see here i've already edited it and let me show you what the previous one used to look like the previous one used to look like this just some dummy data so what you can go ahead and do in that dummy data is um once you go inside of that db.json file you can go ahead and click edit and you can put whatever json you want here so the json i have is this user object and pretty much the user will just have an id a name i can like maybe add like maybe i'll call this like first name maybe i can add last name which would be sistili and pretty much that's about it so i'm just gonna commit these changes and bam i now have like my own fake quote fake uh endpoint and the way you access it is pretty much just by visiting this url so as you can see it's just my jsonserver.typeycode.com the your github username and then the repo so my github username is a to the y and um this repo is called slash demo so i'm gonna go ahead and go to there so a to the y and then demo and then you can see here it's it generates a nice little ui where you can see you know the available resources and i'm going to click on that user object i wrote and bam here is the endpoint that i can hit for my user data that i want so just a small little trick i thought i would teach you guys it's really helpful when you're practicing and setting up new projects so now that we have the end point we want to hit let's go ahead and look into setting up redox saga so as per the documentation the first thing you want to do is make sure you mpmi redux saga and what we're going to do is because we're using code sandbox i'm just going to go ahead in the dependency list type in redux saga bam and it installs if you are coding this on vs code like most development happens you can just type mpmi redux saga into your terminal the same way you install any mpmi library or npm library and it'll install it for you now the next thing that the documentation says to do is you have to have something called a saga.js and then you have to connect your redux store to redux saga so let's look at the first thing the first thing is they essentially in their saga.js have a bunch of different things so number one is they have the actual handler which is going to call the api number two is they have the watcher saga which takes every instance of the user fetch requested action and will call that fetch user function that we saw above and the third thing is they sort of teach you how to alternatively if you don't want to use this take every keyword they use take latest and i'll explain what take every and take latest is but essentially all you have to know is that's what they are doing so they break it down into a handler and into a watcher and then below that they will show you how to actually set up um redux saga so it is integrated with your actually with your redux store so let's go ahead and do that first so let's go into our redux folder where we have our cons configure store file and you might have remembered this file so actually the first thing i want to do is create a new reducer for the actual data that we're going to get back so let's go ahead into docs and let's call this user.js we don't want to store the same thing that we have in counter because we're storing different data and we sort of want to organize it in the docs method so i'm going to go ahead and copy and paste what i have for that counter stuff so the two actions we're gonna have is get user and that's gonna be get user and then we're gonna also have set user because those are the two things that we want to pretty much do we want to dispatch get user from our component and then we want to dispatch set user once we have gotten the user data and we want to store it now the next thing we're going to do is we're going to create the functions for it so pretty much just get user now usually you would for example if you're getting a user you might pass in the user id or anything like that since this is just a very basic endpoint that we're trying to hit just to illustrate how redux sago works we're going to leave pretty much that as blank but in the next video when we're actually using an express server to get all this data we're going to have a real example in there now the next thing we're going to do is set up our set user function and there we go so whenever i call whenever i dispatch an action that um you know does get user it will dispatch an action of type getuser and the same for set user which is going to be very important for the next step but before that in our initial state let's just set the user to undefined and then down here we don't really need an action for get user because the watcher saga and redux saga is going to handle the get user stuff all we need to do is handle the set user case and in the set user case it's going to be pretty simple all we're going to do is um we're going to go ahead oh and in set user because we are getting a user back from our endpoint we are going to be calling this action with a parameter that is um the actual user that we are getting back the user object that the api is returning so we're just going to do that and then we're going to say the user is user but a shorthand if you're in an object naming the variable the same thing as you're setting it to you can just go ahead and type in a user once and it'll set that so we're going in in to handle this set user action we're going to go ahead and destructure the user from our action and then we're going to set the state to be the same thing that it already is even though we only have user in the state it's still good practice um to do that and i talked about it i think in the last video but we're going to do that except the user is now going to be the new use the user object in our state is going to be the user that we are getting back from our action except uh like i said if you're setting something in an object same to and it has the same name you could just go ahead and set it like that so now that we have that our reducer is all set up and we're going to go ahead and over here import our new reducer so we're going to import user we're going to call it user reducer and we're going to import it from docslash user and then we're going to say user is our user reducer so this has nothing to do with sagas yet we're still just setting up our second reducer um and we're adding it here so so now our redux is completely set up with the new reducer now let's go ahead and set up the actual redux saga side of things so the first thing we're going to want to do is we're going to want to go ahead and import something called the create saga middleware from redux saga and this is pretty much what we're going to use and that's just going to go ahead and create um you know going to be the thing that we actually create the redux saga from it's pretty much just an initialization function that gets exported from redux saga so you don't have to worry too much about that so we're going to call that initialization function and we can go ahead and save it so con saga middleware equals create saga middleware and then the next thing we are going to do is usually when it comes to um redux you might have a couple of different middlewares and i plan on making a video in the future about the different middlewares you can have so what i like to do is create an array of all the middlewares you want for redox saga so for example middleware middleware is going to be equal to array and right now we only have the saga middleware so we're just going to keep the array limited to that but in the future as you add on more of reducer middlewares uh redux middlewares like redux logger for example um you can add them to this array now the last thing we're going to do is pretty much over here we created the store and we just passed in the reducer but what we didn't actually do is pass in any actual arrays for middlewares that we want in there as well so what we can do is up here in our redux we can also import something called apply middleware and in the third parameter so the second parameter is just going to be an enhancer and we don't have any enhancers right now and i'll talk about enhancers later but we are going to add our middleware so we're going to call the apply middleware and we're going to pass in we're going to pretty much spread all the middlewares that we added in here essentially all we're doing now is we're saying okay when we create redux i want to create redux the same way we've been doing before with all the different reducers we have but i also want to add a middleware and that middleware is going to be redux saga and i want it so that our middleware redux soggle will actually listen to anything that um any dispatches that we make through redox and that sounds a bit complicated but once you see how it works it'll be a lot easier so the last thing we have to do in this file is we're pretty much just going to run our watch as sagger so watch your saga and the watcher saga is something that runs constantly in the background and it listens for any redux actions like i said before it'll listen for any redux actions so that it can map it to their handlers whoops so before we can actually run it we have to create it so let's go ahead and create a new directory for our sagas so we can call this you know sagas for example and on the top level i'm going to create something called a root saga and this root saga is where i like to put my watcher saga and all that good stuff in there so essentially what you want to do is we can go ahead and import a couple of things from redox saga so first thing we're going to import take latest from redux saga slash effects okay the next thing we're going to do is we're going to export a function now with this function this function and most of the functions that are within the redux saga ecosystem are what are known as generator functions so when you have a generator function in javascript i won't go too into detail they just allow you to do asynchronous things a bit easier and there's a lot of other benefits when it comes to um generator functions however i've never used one outside of the redux saga ecosystem so for just learning redux sagger purposes we're just going to sort of go over the basics and taxes so the first thing is when you declare the function you put a little star after it and now we're going to name our function let's call it the watch watcher saga now in this watcher saga what we want to do is two things well first of all this is going to be where we look for any actions that have been dispatched by our redux store um and we map it to the handler functions that will actually call the requests that make the api calls so before we do that now that we just have the watcher saga set up what we can do is we can go ahead into configure store and we can uh call saga dot run on it so saga middleware dot run and then we can pass in our watcher saga that we have imported from here and pretty much that's just gonna set up a listener so when we call this you know this whole file gets called at the beginning of the application's life cycle and it'll just be like okay we want whatever is in this generator function to just constantly be running in the background listening for any redux actions that are going to be dispatched now the next thing i like to do is in my sagas i like to create a new file for the requests and i like to create a new file for the handlers and let's go ahead and look at the request first so i like to name the files the same as our reducer so for example we're going to store all the requests that have to do with users in this file so we're going to call it user.js as well and now in this request file what we can go ahead and do is first of all just like any other api request we're going to go ahead and import axios and then next thing we're going to do is we're just going to export a function that just makes the api call so we're going to export a function and that function is let's call it like request get user and in this we're not taking any parameters we're just making a simple api request and what we're going to do is return axios.request and if you remember from my video it's pretty much just going to be the same as this so axios.request except we're not actually going to pass in um we're not actually going to have a dot then a function we're going to actually pass in the request as a map and have it return the promise for that request because we're going to be asynchronously calling this with a yield on the handler side and that might sound a bit confusing but you'll see what i mean in just a second so when you call axial stop request and pass in sort of an object what you do is you first pass in the method so in this case we're making a get request so the method is going to be a simple get you pass in the url that you want to hit so if i find uh where was it over here so this is oops this is the url we're going to hit the url of the json server that we set up and pretty much if you had any other parameters like for example if you were calling this with authentication which we're going to cover in a far greater video you would use something called with with credentials um if you're making a post request you might add data and stuff like that um all of that stuff we don't really need all we need right now is to say that we're making a get request and the um oh did i say user sorry that should be url we're making a get request and the url for that get request is this and that's it so that's our entire request now let's go into the handler the handler is sort of what connects the root saga to the actual request and what this handler is going to be doing we're going to call it user.js as well because this is going to be the handler for anything that has to do with the actual um with the actual uh root saga so what this is going to do is it's pretty much going to be like okay i want to call this request function and i want to store the data in our redux store so the first thing we are going to do is let's import call and put from redux saga effects and the next thing we are going to do is we are going to create a function it's going to be a generator function as well and let's say for example like handle get user and in this handle um in this handle get user we can go ahead and essentially take in the action because when we call a redux action when we dispatch a redux action all that data that comes from it is going to be inside of there but because we are getting the user and we're not taking in any parameters from this action we don't actually need it so we can delete that if we want i'm going to leave it just for demonstration purposes um now the next thing we can do is we can wrap our call around in a try catch so we can say response to our api request is going to be yield which is sort of like a weight if you've ever done a weight but it pretty much says um because most api requests are asynchronous it pretty much says we are going to wait for this call to finish before we move on and what is what are we going to call this call is a keyword from redux saga we're going to call that request that we just set up request get user we're going to pass in that function and let's go ahead and just uh make a cache with an error and let's console.log the error here so if it makes an error for now basic error catching we're just going to console log the error nothing too crazy and if so now we can do something like for example we can say okay our data the data that is coming back is going to be equal to the response and we know that the data that is coming back here oops the data that is coming back here is going to be that user object so now the final thing we can do is number one we've made the resp uh the request and number two we've gotten the data out of the request and now number three we want to store that data inside of our actual um reducer and the way we do that if we go back to our reducer as we can see here we created a set user action that once you dispatch that set user action it'll set the action over here into our reducer store so let's go ahead and give a so the way you do that is you called yield put and then you pretty much call the set user action and then you pass in whatever that user is so i know that sounded a bit complex and then the last step is to pretty much connect the actual action of getting user with this handler function because this handler function is what's doing everything right if you remember for the diagram it's um it's pretty much making the request and then once it gets the request it's calling that set user function back to store the data that we are getting from the request so the way we connect the get user um action from our reducer to this handle get user action in our redux saga handler is through our root saga or watcher saga so what we can go ahead and do in this file is we can essentially call the yield take latest and then we connect the two together so we connect the get user get user action with the handle get user function and this get user we just import it from our redux store just like that now what is going to happen oops i need to install the dependency axios don't forget about that okay so now what is going to happen here let's walk through the flow before we actually run this code when a get user action is dispatched our watcher saga will take that action and call get user that get user will then call our request get user which will hit make a get request this endpoint and return oops and will return data we will then take that data and yield put is redux saga's way of dispatching a redux action it will dispatch a redux action that will set the user to be whatever the data that we got back from the endpoint was and if we look at our user object pretty much our user will just be that so let's go ahead and try this out let's just go into our app.js let's create so the same way we created a use effect to call this um here we can go ahead and create another use effect let's go ahead and import that from rita react and instead of calling axios all we're going to do is we're going to dispatch an action and if you remember to dispatch an action simply what we're going to do is we're going to um create our dispatch act our dispatch function using the use dispatch hook from redux all right and in here all we are doing is we're going to call dispatch get user just like that oops now what is going to happen here is as soon as the application is rendered we are essentially and react sorry react might give complain and say for example in this little array since we're using a dispatch function it's technically a dependency for this use effect you can go ahead and add that to the use effect dependency array it's not going to make a difference because this dispatch is not going to be changing anytime soon so this use effect will still run um the first time that the component is rendered but anyways so let's go ahead and see what is going on here let's see if we can get the user um object from our reducer and if you don't remember how to get that essentially all you have to do in order to get a um in order to get sorry a redux variable out of the store is you essentially uh just use the use selector hook so in this case we want to get the user object and that is coming from the user reducer so instead of having the count for the count reducer we do it like this and um we call take it from the user um reducer and we're taking the user object from the user reducer so now we can go ahead and let's console.log user so what i would expect to happen here is number one first i would expect this user object to be undefined because this is going to run before this api request finishes but then after it is undefined it should be the data um this data that we are getting from here um so let's go ahead and see what happens so we get an error here that says take latest requires a pattern or a channel and if we look at this essentially we are importing get user from ducks user but i realized i forgot to actually export that that constant so all we have to do is export it over here and we will see that there we go the first time it runs and sorry if you can't see the console too clearly but the first time it runs we get an undefined for user but then we actually end up getting the user object from our reducer which is amazing that means the request went through and it all worked and if you're wondering what that take latest actually means so there's a couple of these and the redux saga documentation actually touched upon them so for example there's then take every and take latest take latest what that means is when you dispatch a get user call it will let's say for example you dispatch two get user calls one after another it would if the first request was not done yet if the first take uh um get user request wasn't done yet and the second get user request was um called it would simply cancel the first one and take the latest of it so if you have for example an api request that for whatever reason repeats itself before it actually finishes take latest would make it so that only one of them will actually get completed but if you for example use take every instead that means every time the api request is called every time that action is dispatched for get user even if the previous one didn't finish yet it will create a separate thread and asynchronously call the endpoint again so for example if we were to call this endpoint a bunch of times depending on how long it takes so let's say for example let's dispatch another getuser you would see here that if i go ahead and refresh it we are setting the user twice now because every time we dispatch that get user action because we are using take every um it's going to not cancel it if it was called twice in succession but if we switch this back to take um oops to take latest latest there we go if we switch this back to take latest you'll see here that even though we're calling the api twice because it doesn't resolve and finish before the second request is done it will only set it it will only finish and set the actual data once so that's sort of the difference between take every intake latest and there's a whole bunch of these takes there's like uh for example there's like a take leading a take maybe if you want to add some logic there's a whole bunch of them um but for you know just learning purposes we're just worried about the take latest and now that we have the data we could do whatever we want with it for example like i could go ahead and dispatch like i don't know i could like const like um sorry i can be like h1 like hello and then like user.firstname or whatever uh first name and you know when it first renders it'll be undefined so i can be like i can add some conditional logic like what we did in the first couple of videos in this series where if the user is undefined it's not going to display hello but for example here if i refresh it you'll see here it doesn't display it until the request actually resolves and my name is there but yeah that is pretty much it for redux saga to recap the flow of things now that we have everything completely done let me make the code as big as possible the first thing we do is we dispatch a get user action and we set up our redux saga so that it watches for any actions that gets dispatched by redux within one of our components and when it does this watcher saga will look out for specific actions and map it to its handler functions those handler functions will then call our request function that makes the api request then returns the data to our handler function which will then set that data from the api request back into our actual redux store which we can then access in any component of our application and that is pretty much um the tldr of what redux saga is doing in our next video we're going to be going over setting up an actual express server and actually connecting to that express server using redux saga um and uh all locally so where we might uh also in the video after that throw in some more complex requests so you can see how the functionality of redux and redux saga and axio sort of builds on as your application gets more complex so like i said if you found value in this video please consider leaving a comment it really helps get these videos out there to more and more people with the youtube algorithm and subscribing and turning those notifications on so you get notified when i put each one of these videos out thanks for watching and i hope you're all staying safe and i'll see you guys in the next video
Info
Channel: Anthony Sistilli
Views: 44,886
Rating: undefined out of 5
Keywords: react js, reactjs tutorial, react js for beginners, react js project, react redux, redux saga, react redux tutorial, react redux tutorial for beginners, add redux saga to create react app, redux saga create react app, redux-saga tutorial, reactjs redux, redux saga middleware, redux saga cra, how to add redux saga to create react app, redux saga explained, redux saga hooks, redux saga advanced, redux saga react, redux saga api call, redux saga multiple api calls, takeLatest
Id: 1K26DIKt3w8
Channel Id: undefined
Length: 35min 21sec (2121 seconds)
Published: Sat Nov 28 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.