Fetching Data in React - Complete Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
what's up guys Terrace cousin here welcome back to another react tutorial in this one we're going to take a look at fetching data in react this is going to be a video covering the basics of fetching data in react and all of the things that you have to think about to make that happen for example loading right how do you handle loading when fetching data in react what about errors would you do if there's an error how do you handle race conditions these are all things that we will talk about and cover in this video so make sure to watch the entire video Until the End because if you do chances are you're probably not gonna have to watch another video on data fetching in react ever again sound good cool let's jump on my computer screen and learn about data fetching cool so we're now in my computer and I have set up here a very simple application that we're going to use to fetch some data in react now the first thing that I want you to look at is this base URL right here this is going to be where we're fetching the data from in this application we don't have a backend it honestly do not make sense to make a whole backend for this so we're going to be using this Json placeholder which is a public API that returns to us some Demi data like posts comments and users and some other entities I believe and we're going to work with this in our code what we're going to work with is this post entity here so I've created here an interface called post which has an ID property of type number and a title property of type string this post is going to be set here in our state so I've created here a state variable called posts which holds an array of posts and we're going to use this to get the data the posts from the API and then put them into our state and then here in the body of this component we have this unordered list where we're rendering each post one post at a time so currently we have our app here right if we reload the page there's nothing in the app there's nothing happening because we're not actually fetching any data so let's start fetching data what I'm going to do is I'm going to create a use effect use effect I'm going to just put the basic function definition of it with an empty dependency array and the in this use effect I'm going to create a function that is going to fetch our posts get the response from the API and then set our state posts to whatever it gets from the API so let's build that let's put an enter here and let's create our function this function is going to be called fetchpost and it's going to be an asynchronous function which means that we have to put async here and then we open the parentheses and then we open the curly brackets now inside of here we are going to want to fetch this data so the way we're going to do this is we're going to be using fetch from node.js we're not going to do anything fancy with axios or react query we're just going to perform a simple fetch so that you can understand how that actually works and all of the things that we have to build on top of it to make this fully functional and Bug proof so we're going to do const response and this is going to be the response that we get from the API and because this is an API this is an asynchronous action we are in an asynchronous function we're going to have to await that response so we'll do a weight and then we're going to fetch and then the fetch the syntax of fetch is you have to provide the URL so we're going to do backticks because we're going to be using this base URL right here so we're going to do dollar sign curly brackets and then base URL and then we want to get the post so there's an API definition on this website that you can go check out but the one for the posts is slash uh why is this slash posts so this is going to fetch the base URL which is our JS Json placeholder API and it's going to fetch the post's endpoint now this is going to return to us some response if we hover over this you're going to see that this is a response this is the response object that we get back from Fetch now this one we want to get its data which is going to be in Json form so we need to manipulate it we need to call the dot Json function on this response so what we're going to do is we're going to create a new variable on the next line we're going to call this one posts and we're going to do equals a weight because this is also an asynchronous operation and then we're going to do response dot Json now don't worry too much about this because this will depend on how you're fetching the data if you end up using axios or something else you may not have to do these steps so it doesn't really matter the syntax of them so really don't stress out about this what matters and what is really important here is that we are getting a response from the server from the API and we're converting that response into Json into something that we can actually use so that we can put this in our state so that we can put this in our post State again depending on how you do this this might look different so don't worry too much about it just worry about getting the data from the API and being able to put this in state now if I just hover over this you're going to see that post here is of type any now this is fine nothing is going to break but I always like to have proper types in my application code and because the way that we set this up typescript has no way to actually know what this response is what data this has because we haven't provided a way for it to know like it doesn't it can not know just by this URL so we have to manually Typecast our results into the entity that we expect in our case that is an array of posts so we'll do as and then an array of posts so this really it does not a thing we're just telling typescript that hey we know this is an array of posts so trust us and this will now have the type of post which is great because we can now come in here and do set posts and then posts so we are taking the data from the Json that we got and then we are setting it in the state of posts now I saved and nothing happened on the right that's normal because we have not called this function here so what we need to do is we just need to call fetch posts on this use effect which is going to call it on Mount and voila we now have posts in our application these are coming from this API right through this function right here which is getting it converting them into actual objects and then setting the state for that so that is great we have now achieved the minimum that we need to have data fetching in react we've successfully created a full end-to-end API call to get some data from an API server which is great now we need to take this a step further if you notice here if I refresh you're probably not going to see it because the data that we're loading is quite small and my internet speed is quite fast so this happens very quickly but before the posts are actually rendered we see a blank screen minus the header here we see that there's nothing here right and then the posts pop up this is because we haven't set up any loading in our application we're just straight up fetching the posts from the API and returning them and once we have the response we're setting the state to our posts there's no visual indication that that something is going on and this is bad because you can imagine that if you had an application where things would take longer perhaps you're loading more data or the user's network is slower than mine then the user would have no idea that something is happening they would have no idea that a fetch is actually going on and that's a bad user experience because they might think that something is broken they might be waiting there impatiently or they might flat out leave the application never to use it again so you always want to show the user that something is happening and in our case we want to show the user that some data is being loaded so what we're going to do is we're going to create a loading state for our request and we're going to manage the loading State before the request and after the request so what I'm going to do is I'm going to create another piece of state and I'm going to call it is loading and then I'm going to do set is loading as usual and that's going to be State and that's going to default at false man it's really hard to type when you're speaking at the same time now what I want to do is before the request is fired I want to set the loading to true and after the request has data has completed I want to set the loading to false and then show the data to our user so what we're going to do is we're going to come here on the line before the request right we're going to do set is loading to true and then after we have set our posts we're going to come back here and do set is loading to false right so this fetch post is going to first set the loading before ever attempting the request then it's going to do the request it's going to await the response of that request it's going to convert that response into Json into objects that we can use and then it's going to set the posts and set is loading to false now we have this functionality but if I refresh here nothing is actually different it's still the same as we had before because we are actually not using this is loading value anywhere so what we have to do is we have to come here and we're going to do something very simple it's probably not going to look too pretty but that's fine what matters here is that you understand what we're doing and why we're doing it we're going to do if is loading we are going to return a div that just says loading again this will not be pretty at all but it's very important to understand what's going on if I refresh here it's going to happen very quickly right but you saw a loading here at the top left if I do it again there's a loading here right we have a brief moment of loading before the data is shown again it's not pretty but it works it's showing that there's something going on cool so now that we have loading an application our application is already much better it's already a much better user experience but we can take it further if you look here at this code we haven't really considered the possibility of this failing of something happening with the fetch request maybe some error somewhere and like our application is not built for that if there's an error here whether is that the API that we're trying to fetch the data from is down for some reason or the user loses internet connection or any other reason or code is currently not handling any error what's probably going to happen is it's just going to throw an error in the console and it's not going to show any data and the user is going to be very confused as to what's going on so whenever you make a request you have to always think about the possibility of that request failing for whatever reason and then you want to handle that failure so what we're going to do to handle this is we're going to create another piece of State we're going to call this one error and then set error here like normal and then use State and then I'm not going to give any types here I'm not going to give anything because this error for the purposes of this tutorial is going to be of type any we don't really care what the error is we don't really care about doing something with a specific error message or error code right we just care about is there an error or is there not an error we could have done this as a Boolean but I think it makes more sense to put the error there because if ever in the future we wanted to do something with the error we could do it because we had access to the error then what I want to do is I want to make some space here right between the different sections of the code and what I want to do is I want to wrap the actual fetch the actual trying to get of the data inside of a try catch block so that if something happens in there we can catch the error that comes from that and then handle it accordingly because this is the only place where an error could happen the error Could Happen only when refreshing the data and converting the data to something that we want to use in any other place we're only setting state so there's no error that could possibly happen here so what I'm going to do is I'm going to create a try catch block and then I'm gonna do catch and then for now we're just gonna do it like this I'm gonna put these two lines of code inside and also what I'm going to do is because we're having this post here and that we want to set the post this set post should also go inside of this function otherwise we won't have access to post right in JavaScript in typescript everything functions on Scopes right and the scope of this post is only within this trike catch block so our set post has to also go here now we have the sketch block which means that any error that happens here is going to be cut and we can do something with it so what you can do in catch I hope you know is you can do e here for error or you could also do error here it's really depends on how you want to do it we're going to do e and then inside of this we're just going to go and set error to E right and now typescript is going to complain that e is of type unknown which is fine for the purposes of this tutorial we're just going to do any and that will solve our problems so what this code is now going to do is it's going to set the loading to True right that we want to do regardless then it's going to come in here and try to run this code here it's going to try to fetch the posts if that goes successfully it'll have the post here if it can convert to the post successfully then it will set the post this is our success case this is the case where things went right if not if for any reason there's an error we then catch the error with this piece of code here and then we set the error in our state this way if anything goes wrong we have the error and we cannot do something with this error so what we're going to do is just like we did is loading here what we want to do is if error again we don't care about the type of error we just care that there is an error what we can do is return the same way a div that says something went wrong please try again right this is at least a basic UI to show the user that hey something went wrong please try again in this case we have no way to provide them to try again there's no like refetch button or anything they would have to just refresh the page and try again and that's fine this is a tutorial so let me just show you if I put this to true just so you can see how the UI looks right this is the error scenario if we ever get an error this is what the user would see again it's not pretty but it does the job I'm just going to remove this and put error back again so now we have error in our federal guest there's one more thing that I want to mention about this is that this is loading here it's fine right it'll work right if we just refresh the page there's usually no error so it'll be fine however I would always like to put this in a finally block here instead because this makes it a bit more cohesive a bit more easier to understand this code will first try this fetch right and then if it's successful it'll set the post if there's an error it's going to handle the error but then regardless of what happens error or not we always want to set loading to false because if you look here where we're actually returning something if it's loading this is before the error and so if we forget the set is loading to false what's going to happen is is loading is going to be true and this will never hit even though we have an error right so the reason I want to put it and finally is that it's more clear that whatever happens with this try catch block whether or not there's an error it is always going to set is loading to True again we could have left it here like we had before right we could have done this but I usually prefer to put it inside of this because then it makes one cohesive block that kind of handles all of the functionality that we want from this request cool so now we have have loading and error set up in our application which is great our application is almost complete there's just one thing that you really have to think about that is super important so make sure to watch this nice section because not a lot of people think about when building requests in react so the way we currently have it now is that this is only ever going to be fired once on Mount that is what this use effect does there's no there's nothing any dependency array which means that it'll never fire again but the truth is in a lot of applications your requests do fire multiple times based on a set of dependencies for example pagination right maybe you don't want to fetch all of your posts at once because you probably have thousands of them and that would be too much to fetch all at once and so in that case maybe it's a better idea to fetch them in batches of 10 or 20. if you do that that's going to require you to do multiple requests one request for each page loading the specific chunk of posts and that if you do that if you file multiple requests you open yourself up to having some race condition problems and some very strange bugs that can be really hard to debug so let's look at one of such examples let's create now a new piece of State called page set page and then we're going to do use State and that's going to default to zero and now what I'm going to do is I'm going to pass this page as a parameter to our fetch request so I'll do question mark page equals page and now because we've added this in our use effect react is going to complain that we have a missed independency so we're going to put page here and now every time page changes we are going to fire this request with the new page now keep in mind I don't actually think the page does anything in this specific API endpoint that doesn't matter what matters is the concept in many applications you're going to have to pass query parameters to your request so this is a valid example so again doesn't matter that this doesn't actually function we get the same results whether or not we provide a page what I'm going to then do is I'm going to add here a button and I'm going to do on click that button is going to increment the page so set page Page Plus one so we're going to do the page page plus one and that one's going to be called increase and then we're just going to put the page here so that we know kind of what page we are on so we have here now this button that every time I click it as you can see it is firing a new request with the updated page but we're always getting the same data because this API doesn't support it again that's fine that doesn't matter now let's think about this example here right what happened now is we're on page zero this use effect fired with page zero right so the data is loaded in our case the data is instantly available but let's pretend for a second now that we're in a different environment and for whatever reason this initial request with page 0 took five seconds to complete maybe the API was down for a second and it delayed the response for my API call what happens if let me just kind of illustrate this if I put this to true just so we can kind of see and actually we are going to do something we're going to move this away because we want to have access to this button while things are loading so what I'm going to do is I'm going to do is loading and and div loading and then here I'm going to put is not loading and I'm gonna put this year so I've just made a slight modification to our UI so now even if this is loading so I'm going to set loading let's put loading here to true just for purposes so that you can understand what's going on if loading is true we still get access to the button which in many applications will be a valid thing right it's not like your entire UI is going to disappear just because some section of it is loading right so back to our example we have the first request with page zero and for whatever reason that request takes many seconds to complete and then we're faced with this UI here this is loading and this is loading indefinitely what happens if we then press this button while it's loading and increase the page to one well if we look at our code that's going to trigger this use effect here to fire again this time with the new updated page which is page one and that's going to fire another fetch request to get the next page of posts now let's say that for whatever reason when that happened the server is now back up and running and it's fast again and this response returns immediately right we still have that previous initial request with page zero that one is still pending and at some point that one is going to return the response and when it does it's going to come here and it's going to set the post to the value of that response but this is going to happen after the request of page one which means that it's going to overwrite the most up-to-date value the page one which is our most up-to-date state is going to get overridden with the results of the previous request this is bad and this is what we call a race condition it happens because we expect one order of things to be in right page zero and then page one but the actual order that we get is not necessarily the same it can be page one and then page zero depending on a wide variety of factors so we have to be careful about that because this is a race condition and they don't always happen right that's the nature of a race condition it doesn't always happen it really depends who finishes the race first but if they do it's very difficult to debug because you're often you're confused as to why you're seeing results that do not make sense so we're going to fix this and the way we're going to fix this is we're going to fix this by making sure that before we fire any new API request we cancel the previous one we abort the previous one if it exists if it doesn't exist if we're fetching the first one then there's nothing to abort then we don't have this problem but as soon as we try to fire another request and there's still one already pending we should abort that request instantly and then fire the new one don't get scared this is this might sound complex in theory but it's actually super super simple and we're gonna do that just now so what I'm I'm going to do is I'm going to create an abort controller and we're going to use that abort controller to handle this use case so I'll do a const abort controller ref because this is going to be a ref so that's going to be use ref and then I'm going to give it a type of abort controller this is a default type in JavaScript or null because this will start out as null then what I want to do is I want to remove this loading through here we want to get back our actual behavior and then what we want to do is we want to like we said before doing any requests we want to make sure that the previous request is canceled so what we're going to do is we're going to create some space before this set is loading here and then we're going to do a board controller ref dot current dot question mark because remember this can be null dot abort so this code will abort the request the abort controller if it exists right and then what we're going to do is we're going to do abortcontroller ref.current and then we are going to set a new abort controller so a new abort controller and we are going to then pass this new abort controller to our request and the way you do that is of course this might depend on the library that you're actually using but you can just pass the signal here with Fetch and then we're going to do abort controller ref dot current question mark dot signal whoops cool so let's just take a moment here because this might be a little bit difficult to understand and I can totally understand that so we've created an abort controller ref which can be of type abort controller or null so a board controller is something default that you get in JavaScript in typescript that allows you to call the abort function on it and then cancel a request and that works through this signal here that we're passing to our fetch so then in our fetch post function what we're doing is before we're even attempting anything related to fetching even before we are setting loading to true we are canceling the abort controller if and only if it is there and remember this starts out as null right so in the first request this will be null so there'll be nothing to abort then we are creating a new abort controller and we're assigning it to the ref this is how we're doing it through this dot current property and by the way if this is unfamiliar to you I do have a whole video about use ref and how you handle refs and I would strongly recommend that you go watch that because this is used in understanding this so we're setting this aboard controller this ref to a new abort controller and then we are setting loading to true as we did before and we are passing the signal of that abort controller to our request this is what is going to enable us on the next request so when page now becomes one this is no longer going to be null it's going to be the value of this one and if we call abort on it it's going to cancel the previous request and then it's going to set a new abort controller for a new request and it's going to get past here to this fetch here it's very important that you always set a new abort controller because you cannot reuse the same abort controller on requests as soon as you use one request and you abort it you cannot use that same abort controller again you have to create a new one and then import it again and so on so now we've essentially guaranteed that no new request is ever going to be fired before canceling the previous one if it exists now there's one more thing that we have to change here and it's inside of this catch Block in in react and in JavaScript and typescript in general whenever you cancel a request that will throw an error and that is not good because then we're going to set an array here and we're going to show the error UI to our users and we don't want that so we need to handle the case where the user has canceled our request so the way we do that is we can check the error if we do if our e dot name equals and I believe it's what did I put here abort error if that is true what we want to do is just console.log aborted and then we want to return because we do not want to set this error here in that case and I'm just going to make a little bit of space here to just kind of make it easier for us to read so if the error's name is abort error which is going to be true only if it's a cancellation error if this request was canceled by the user then we just console log aborted for our own information and then we return so that we do not set the error and thus trigger our error state so now if I rephrase this application I'm going to spam and actually open up the console here too let's move this up just a little bit and I'm going to now spam this here right you see only one aborted because really my internet is quite fast but if I go here to network and maybe slow down this yes to fast 3G and do it here where's the console there's the console yeah so you see it's quite fast but yeah there you go now we're getting all of these aborted right if I just do it normally it's going to load normally press it normally it's going to load normally normally again but if I spam it right you're going to see all of these console logs here that are aborted this means that our request is being aborted before the next one is fired so this again guarantees to us that we will never have a race condition in our application ever again and that before firing any request the previous one is always going to be aborted cool so with this honestly we've kind of covered the basics of data fetching in reactors not that much more to it now again we've had to do a lot of these things manually right like handling our own error States our own States and so on and there are better solutions for that for example react query that's a great solution because that literally handles everything that we've talked about here in pretty much one line of code and I would strongly recommend that you check that out and implement it because that is how I Implement my data matching in react but for this video it was really important that you understand the things that you have to think about when data fetching loading error race conditions so that you really understand them and know why they are required and what can happen if you don't do this properly because with this knowledge you can then go ahead and use tools like react query or some other fetching tool and be fine with it even if they do a lot of the work for you because you now understand what it means to actually fetch data in react so please do really take the time to really think about what you've learned here and try applying this on your own because this is really crucial and any application will have some sort of data fetching and you're gonna have to deal with this one way or another cool so there you have it that was Data fetching in react now before you leave hold on because there's something really really important if you want to learn more about react if you want to get access to me personally to be able to ask your questions about react to submit your code have me review it I have built a Discord of react developers it'll be the first link in the description it's completely free you can join you can meet other developers just like you and have direct access for me to answer all of your questions and learn everything there is to know about react I'm really trying to build the best and biggest community of react developers there ever was and so if you joined that would mean the world to me and I would love to see you on there also if you've enjoyed the video as always make sure to leave a subscribe leave a like because it really does help me out a lot it shows me that you enjoy my content and that you want to see more of these videos which I will make and with that being said my name is vendors cousin this is causing Solutions thank you so much for watching and I will see you all in the next video ciao
Info
Channel: Cosden Solutions
Views: 35,185
Rating: undefined out of 5
Keywords: react tutorial, react crash course, react developer, learn react, react hook, react hooks, react hooks tutorial, useeffect hook, useeffect tutorial, programming tutorial, react hooks explained, computer science, tutorial for beginners, react component, learn programming, web development, frontend development, coding for beginners, simple code, easy programming
Id: 00lxm_doFYw
Channel Id: undefined
Length: 29min 10sec (1750 seconds)
Published: Thu Jun 15 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.