React Custom Hooks with Axios Async useEffect | React Tutorials for Beginners

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] hello and welcome hi i'm dave and today we're talking about creating custom hooks in react now this tutorial is part of a learn react tutorial series and i'll give a link to the full playlist for the series in the description below you can see i've got visual studio code open and i've got the blog project open that we've been working on in this portion of the learn react tutorial series i've already got json server running as you can see here in the terminal and in the other terminal window i've got our react app running so i can close the terminal window and if you're not sure about setting those up please view the previous tutorials in the series okay with both of those running and visual studio code open i'm going to minimize it at first and here is our blog application now we're going to apply a custom couple of custom hooks that's a tongue twister a couple of custom hooks that we're going to create today but before we do that we need to look at the rules of hooks for react and there's just a few to remember here one a very important one is only call hooks at the top level so don't call hooks inside loops conditions or nested functions and then a couple other things to remember call hooks from react function components and call hooks you can call hooks from custom hooks so those are the places we can call them we can't call them inside of other existing react hooks like use effect and we can't call them inside of regular javascript functions either but we can make our own custom hooks and then we can use other hooks inside of those so with that said let's look at just a couple of other things very quickly i want to call your attention to this website and i'll give a link to it in the description below but it's a collection of react hooks because that's what these are they're kind of like utility functions but they're in react and they all start with use which is another rule of react hooks actually that we need to define them with the word used to start out with and they're like recipes so there can be more than one hook that accomplishes the same thing just because it's had a different author and this is a good site to search for those on also there is this npm page that's react-used and it contains several react hooks as well that i think are good so i'll leave a link to this in the description below as well i just wanted to draw your attention to those before we come back to our own blog project and create these hooks so now let's get started in visual studio code here in vs code i've got the app.js file open but this is just at have the place in the tree open that we're going to create our hook actually what i want to do is select the source folder and create a new folder inside of it i'm going to call it hooks now you can see the little icon i've even got here with the hook so if you get the icons i believe it's vs code icons extension that i have you'll probably get something similar we can create files of course now inside this new directory or folder if you will and i'm going to call this file use and that's how we want to start out with every react hook and then window size this is a simple hook that will allow me to display how a hook is used to start out with then we'll create a more complicated one but we'll start here with use window size now inside this hook i'm going to import use state and use effect because we can use these hooks inside of our custom hook and now i'm going to say const use window size and set this equal to an arrow function now inside the function we'll start out with a window size and a set window size so as you can imagine this is going to use state and now we'll set the state equal to something we haven't seen previously in this learn react tutorial series and this is an object and i'll set a width and i'll set this to undefined because that's truly what it is at this point it is an undefined value and the same for the height so this will get both the width and the height of the browser so we can identify that in our application now after we've set our initial state we'll use effect as well an arrow function there now for the use effect dependencies that we'll have at the bottom we just want this to run at load time and essentially that is the only time this will run just as we've discovered with use effect in other parts of our application now let's define a function right here inside of use effect and we'll call this handle resize so this is if the window is resized and we'll set an arrow function here and now we'll set the window size or set our window size state inside of this and we'll start out with the width and this will be window dot inner width and then the height will be window dot inner height and that will essentially track the value of the window size if this function is called into action okay now that we have that we need to go ahead and call that in our use effect so we'll have handle resize called into action because we want it to run at load time and that's what will happen here now that's the only time this would actually uh run this function handle resize so we'll get those initial values so how will we get the values to continue to adjust when the window is resized well we'll do that with an event listener like we would in regular old javascript so we'll add an event listener to the window window.addeventlistener and we'll listen for the resize event and then we'll handle the resize call that function into action and that's essentially what we need to get those values every time because we added this listener at the beginning with use effect when it was loaded so it only adds it once but there is something else we need to do and it prevents a memory leak in our applications and that is to remove the event listener fortunately use effect has a cleanup function that will only run when the dependencies change for use effect and so we know the dependency won't change here this is only at load but it would actually happen on a say if i change the file and reload so we'll be able to see that happen but also it would happen when the application closes out it would essentially run the cleanup function and remove that event listener so we can do that i'll just define clean up here with a camel case capital u set this equal to an arrow function and we'll refactor this in a moment because we can make this a little simpler but i want to put a console log statement in here so you can see what happens and we'll say runs if a use effect dependency changes and then we'll see that in the log when this runs and then we'll call window dot remove event listener and this will be the same resize event and we'll be removing the handle resize function from that event and now we can save this but we haven't called cleanup into action yet we just defined cleanup so all you have to do in use effect to use the cleanup is the return at the end so we'll just return cleanup and now that would be called into action okay we're almost finished with our custom hook but before we finish we need to remember to go ahead and return the window size in our hook this is not in the use effect which stopped right here but this is in the custom hook where we're returning the window size value and now all that is left to do is export default use window size and we've completed the custom hook file if we scroll back up we can see we start out we have use state use effect we define the hook we set the state we use effect and then the key part here is we want to call it once at load time to call the function we've defined here handle resize but then we also want to add an event listener and so any time the resize event fires we continue to call this handle resize function and then another portion of this is the cleanup function and that's also important to prevent a memory leak so now we have completed this entire custom hook and now let's use it in our application we'll go back to the app.js file and inside the app.js file where we have our imports underneath the api import we can import use window size and you can see visual studio code helped out here it is from dot hooks slash use window size so that is exactly what we need and we can save our file there but we're just not using it yet after that we need to come down underneath where we've defined history and we'll just pull the width out remember we had an object that had width and height we only need the width for what we're going to accomplish here so we'll use window size but we'll destructure and just pull the width value out so now we can save we'll go ahead and remove this extra line above the or underneath the import of use window size and then i'm going to scroll down where we're going to use the width and we're going to pass it into the header so now we just want width equals width and that should complete the changes to the app.js file now we need to move on to the header js file let's go ahead and add width into the destructured props at the top of the header file but now we also need to do an import at the top we're going to import fa laptop fa whoa that changed that completely we said something too close in our date f fns package here we need f a laptop and then we need f a table alt tablet alt sorry i spelled that wrong tablet alt and finally f a mobile alt and these are from react dash icons slash fa and i am not so sure that we have react icons installed in this project yet let's take a look at our package json and we do not have react icons installed yet so i need to go back to the terminal window there we go because it doesn't have react icons we got an error where we had react running i'll stop that temporarily and i'll do npm i react dash icons and we'll install react icons quickly react icons has finished installing and we can see that in our package json added to the dependencies so now i'm ready to restart the react application as well and with the react application restarted we'll go back to visual studio code and i'm going to close out the terminal window again and go back to the header js file here's where we're importing some icons from react icons and these are font awesome icons that we're going to use in the header based on the width so now that we have the width destructured along with the title we can use it here inside of the header and so now let's base this upon the value of the width and so i'll type width and then we'll say if it is less than 768 and this will be a ternary statement we're going to use the fa mobile alt not mobile mobile alt there it is icon and then we can say if the width is less than 992 of course this is the false indication so at this point it is already 768 or greater but at the same time if it's less than 992 we can say oh we'll start another ternary statement and then we'll say if this is true we'll have the fa tablet alt and then finally if that is false we'll just show the fa laptop value there it is and this will essentially indicate in the header which size we are showing so if we're showing a mobile phone view it should show a mobile phone icon if we're in a tablet view it should show a tablet icon and if we're in a laptop or anything larger than a tablet actually it should show the laptop icon so let's save these changes and now let's go ahead and look at our application and see if the changes are in place and yes right now we have a laptop icon in the top right now let's go ahead and open up devtools so we can change the sizing and i will go ahead and start to shrink this down and now it's already at tablet it's a tablet icon if i make it a little larger the laptop will come back there's the laptop tablet and now let's go ahead and change in dev tools to a phone i'll choose the iphone 678 plus and yes we have a mobile phone icon so everything works as expected and i could also shrink it this way and now we have the phone icon tablet icon back to the laptop icon so our custom hook is working and we're sending that width value in and changing the icon based on the width value okay i've changed the screen view now i have visual studio code on the left i have our application running on the right and below i have dev tools open so you see the console here at the bottom and you can see i'm getting a warning that says fa mobile is defined but never used that is because somehow i not only imported fa mobile alt but also fa mobile and i didn't know notice or realize that so let's go ahead and remove that and if we clear out the console and reload we should not get any further warnings that's good now let's go to the use window hook that we created and the one thing i had not demonstrated yet was the cleanup that should log to the window so this cleanup function now if we just make a change to the file because again there's no dependencies here so it just really needs to reload and then we save we should see this message runs if a use effect dependency changes and that's the only way to change the dependency here because we have no other dependency it just runs at the load time so that shows you that the cleanup function does indeed run now we can actually refactor that cleanup function because i wrote it out to allow for this console log and then we defined it separately and i just called cleanup here but what we could do instead of that is just return an anonymous function so let's put in the parentheses and then an arrow for an arrow function and now we can just take this line that removes the event listener and put it right there and that would be the same as having no we need the add event listener the same as having this cleanup function that we call by name or by reference let me hide the file tree and you can see it better so this is our cleanup function and if you see a return at the end of a use effect that is exactly what it is it is a cleanup function and it removes the event listener so this accomplishes the same thing just a little refactor not to be confused with the return at the end of our custom hook but this one is inside of the use effect okay now that we have added a simple custom hook and if you search those links i've given in the description below you should find some other recipes for use window size it's a very popular hook let's do one now that is more complicated but also very popular and you will easily find more literature or more videos on it and that's a use fetch hook but we'll add a twist because we're not just going to create a use fetch hook since we've already added axios to our project we're going to create a use axios fetch hook so let's start by creating a new file and we'll name this use axios fetch.js with that said i'm going to hide the file tree so we have more room to type and now at the top i'm going to import and i'll import use state and use effect once again and these are from react and then i'm also going to import axios from axios and now we'll define const use axios fetch this will be an arrow function and it will accept what i'll call a data url now inside this function we're going to have several pieces of state here and here instead of saying posts we want this to be generic so we could use it in another applications so a custom hook is much like a utility function so here we'll have data and set data and we'll set that equal to use state and we'll put in an empty array then we also want to have a fetch error and a set fetch error and i'll set this equal to use state and it can just be null then we're also going to have a loading state so is loading and set is loading and this could also be equal to null to start out with now let's create our use effect so we'll start with use effect i have an anonymous function and now use effect we're going to define we'll call this is mounted and we really want the component to be mounted and not attempt to apply something after it is unmounted which would also be a memory leak so we'll set is mounted to true and we'll check that status as we apply things the next is to go ahead and define a source and this is part of axios and you can see this in the axios documentation but we'll set a cancel token so we can actually cancel the request if for whatever reason the component is unmounted and we set it by axios.canceltoken.source and so that is our source now we can define our fetch data function inside of use effect we'll set this equal to async and here i'll just call this url as we define this function it can sometimes be confusing to accept a parameter we're going to use and then use that same name when you create a definition because this isn't where we would use it it's just the definition of the function so here i'll call this url and inside of our fetch data function the very first thing we want to do is set is loading to true and then we will go ahead and try and inside the try block we can have a response and we'll set this equal to await axios.get we'll have our url and now we need to go ahead and apply our cancel token and this will allow us to cancel the request if we unmount the component and of course we can handle that in the cleanup but we need to set the cancel token here so here's the cancel token sent with the request and after we get a response we want to check once again to see if the component is mounted and now if it is mounted we can set the data and this will be response dot data as axios has and then set the fetch error to null and as i think about this null that we used above i actually think for is loading instead of null we can set it to false to begin with and then we set it to true when the function is called and then we can set it back to false otherwise okay so we have checked to see if it is mounted and we have set the data and we've set the fetch error to null because there was no error otherwise so now we've finished our try block and now we need our catch block and once we catch an error and i'll scroll up just a little bit we once again need to check if is mounted and if the component is mounted just like above we can set the fetch error now instead of the data and this will be the error.message and we'll set the data to an empty array because we received an error and now after that we'll have a finally block once again scrolling up just a little bit and inside of the finally block so this will always happen once again want to check if the component is mounted but here we'll just say is mounted and so if is mounted is true then we can go to the next part and let's go ahead and use a timeout here just so we can see the loading message we'll come back and change this you wouldn't want this in your final project here you just want to do this to display the is loading message and make sure it's working so we're going to set is loading to false but only after two seconds so that will allow us time to actually see the is loading message and verify that it is working here as we're in development process now that we've completed the fetch data function we want to go ahead and call fetch data and remember the hook receives a data url as the actual parameter so the data url is what will pass in in the definition we used url but above it actually receives the data url so that's what we will call fetch data with after we call fetch data let's once again go ahead and define a cleanup here camelcase cleanup equal parentheses arrow function and we'll say console.log here we'll just say cleanup function so we know it's running after the cleanup function we'll set the is mounted to false and will cancel the request and if the request is already completed no harm no foul but this will only run once again whenever a dependency changes for the use effect with that definition completed let's go ahead and return the cleanup function and now we want to set the dependencies for use effect as well and the dependency here will be the data url that is passed in to use effect or pass actually passed in to the custom hook we have use axios fetch as the data url but then if that changes we once again want to run use effects so we'll put that in as the dependency with that complete we can return three things from our custom hook that's the data that we receive that we have in state the fetch error and is loading so we'll need all three of those things returned from our custom hook and then once again now that the hook is complete we need to export default and we'll use axios fetch and save let's do a quick review before we move on and put this into action so we've defined our custom hook we've imported axios and you state and use effect we set different states here at the beginning of the custom hook we're receiving a data url and then we defined our use effect hook inside here and we set an is mounted status to true and we also define a cancellation token for axios and then we set the fetch data function we defined it and inside of this function we have a try block a catch block and a finally block we're constantly checking to see if the component is indeed mounted and if it is we can go ahead and take action after we've requested the data we can set the data state and of course set the error to null and if we catch an error we're going to set the error message and set the data to empty array and finally this will happen no matter what whether we're successful with the data or we have an error we'll go ahead and see if the component is still mounted and if so we're going to set loading is loading to false and right now we're doing that with a delay just so we can test our is loading message we call that into action with the url received by the hook and eventually we can call the cleanup function here that will cancel a request if the component is unloaded during the request and it will also set his mounted to fault and we're returning the data possible error and the loading status and that is our use axios fetch custom hook so now let's put it into action i'm going to show the file tree quickly just because i want to go to app.js where we can actually apply our custom hook and the first thing we need to do is import it so underneath our import of used window size we can import use axios fetch and this will be from dot slash hooks slash and then use axios fetch there it is and we can save that much but after our import we need to come down to where we've defined the width and use window size and just underneath that we can set const and then equal to and we can destructure what we're receiving from axios fetch and we've got the data the fetch error and is loading and now let's go ahead and hide the file tree so we have some more room and this may still extend a little bit but we're going to set this equal to use axios fetch and now we need to pass in the full url this is not like when we set a base url before we set up our custom hook to be reusable in other applications and so there is no base url currently set so what we need to do is put in the full url for our data and this is json server url you need to change this in a production application but here we've got localhost port 3500 slash posts and that is the full url that we will pass to the use axios fetch now besides that oh and here i set an equal sign there that's not what we need there we go an extra equal sign please remove that if you had that so we've got data fetch error and is loading from use axios fetch but we also need to remove this use effect that we were currently getting our data with because that would be redundant so we can go ahead and remove this from our project but now we have data but we don't have posts so there is one more step after we get our data back and that is to go ahead and set the state as we're using it in the rest of the application we could just use data if all we wanted to do was to display the post data on this page but we're clearly doing more than that with it in the application so i'm going to set a use effect here and once we have this use effect just inside of it i'm going to say set posts equal to the data so it updates our post state and we only want to do this when the data changes and that should complete everything we need so let's go ahead and save and now we have everything in place except we're not using fetch error or is loading but notice we did get our posts once again so that said let's go ahead and put fetch error and is loading to work we'll start by scrolling down and we need to pass these to our home page so here was our exact path with post and home but here's what we need the exact path with the slash we've got post equal search results let's go ahead and break this to another line now because we're going to have more than one prop to pass along and we'll say fetch error equals fetch error and we'll also have is loading equals is loading now that finishes the changes for the app.js file but we need to go ahead and make some changes in the next file and the next file is the home file so let's go to home.js and we need to destructure what we're passing in so we've got fetch error and is loading at the top let's go ahead and hide the file tree once again let's start by just removing everything we have between the main elements and starting over in this file the first thing we'll do is to check if we have is loading so if is loading is true we can put two ampersands and then we can set a paragraph let's give this a class name equal to status message and if we haven't defined status message we will shortly we'll set this equal to loading posts and that's essentially all we need so if that is true we are loading posts so we'll save that of course we're not seeing anything right now but we will here in the near future on the next line we'll check to see if we have a fetch air once again two ampersands another paragraph put the class name equal to status message once again but also let's set a style right here and set this equal to a color and it'll be red because we know we have an error and now inside of the paragraph we can set the fetch error to display and it will be red when it displays now that we have defined that line we can add one more line to actually show what we hope to show and that's not the is loading or the fetch error message but the actual post themselves so here we'll say if we do not have an is loading message and we do not have a fetch error message and now we'll go ahead and say if the lowercase please post length let's set a ternary statement and here we'll set the feed component and this will be posts equals posts i'm going to go ahead and start wrapping some lines here by pressing alt z set post equal to posts then we can close out this component and after we close out the component let's go ahead and put the false part of the ternary statement and this would be a paragraph let's give once again the class name equal to status message and inside this paragraph let's just say no posts to display and save and we once again have our posts now everything seems to be good but when i reload there's our loading post message that's what i wanted to see and it lasts for two seconds and then we get the post so that is correct let me make this bigger now that we're not looking at the console once again i'll reload loading posts and then we get all the posts later so that is good let's go back to the app.js and let's just make an error on purpose so we know that our error message is also working and i'll save after creating a problem with the url and we got a network error let's once again reload we got loading posts and a network error and maybe we could eliminate that where we're not getting a loading message at the same time as the error message so let's go back to home and let's set this equal to no is loading and we do have a fetch error if we save let's go ahead and reload loading posts network error now that looks correct so let's go ahead and go back to our application fix the url and save now we get loading posts and then we get the posts and that's exactly what we want i'm going to show the file tree once again go back to our custom hook let's find that here use axios fetch there it is hide the file tree and let's get rid of that timeout in here so we can just have it to set loading to false and we know about the cleanup function we don't really need the console log here so let's go ahead and remove that as well but since we're doing two things let's define this as cleanup and then call it here and leave that like it is we are setting the is mounted to false and we're also canceling the request with axios so let's save that and everything is good it already reloaded and now when we reload we barely see that loading post message at all so we've created two custom hooks today use axios fetch and use window size and you might find different versions of these out there again they're like recipes or utility functions that you can pull into different projects and use them again and again now remember the rules of hooks there are several and i will link to those in the description below this video hey thank you guys so much for liking the video if it helped you get started with react also i appreciate you watching and subscribing it's helping my channel grow take care and i'll see you again very soon
Info
Channel: Dave Gray
Views: 1,995
Rating: undefined out of 5
Keywords: react custom hooks, axios, async, useEffect, async useEffect, custom hooks, react hooks, react, react js, reactjs, react js custom hooks, react js hooks, reactjs hooks, reactjs custom hooks, useFetch, useAxiosFetch, useAxios, useWindowSize, axios hooks, async hooks, hooks with axios, hooks in react, hooks tutorial, react tutorials for beginners, react tutorial, react js tutorial, reactjs tutorial, react for beginners, beginners, react beginners, js, react tutorial for beginners
Id: tBuceoEGFhI
Channel Id: undefined
Length: 36min 43sec (2203 seconds)
Published: Fri Aug 06 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.