This course has been updated! We now recommend you take the React Performance course.
Transcript from the "Response, Loading, & Error" Lesson
[00:00:00]
>> So this is all of them, they're all loaded at this point, we made the network request and we set it. So you can see, starts out with nothing. It's a pretty fast API mostly cuz it's just reading from a single table in SQLite and sending it along the way.
[00:00:15] So that's cool, but we talked about that ephemeral state around getting our data is are we loading the data, was there an error, right? Cuz right now if we go ahead, we go to Network, and we're like, hi, I'm offline now, and we refresh. Well, hold on, I'm simulating an error, I could also break the API or something like that, that'd be fun.
[00:00:40] Yeah, I mean, I can't come up with a way that I can both turn the Internet off to create a failure, but it will just constantly error right now. We're not gonna do anything, we're not gonna display anything under the page. So yeah, and we don't have a loading state, there are definitely things that take a little bit longer to load an API, right?
[00:01:03] So we wanna might have those other pieces in there as well, so what would that look like? I mean, we could just set a lot more state, right? We could set loading and error and begin to manage all of those, and that's not an abysmal thing to try to do, right?
[00:01:22] So we could do something like, all right, we can assume that it's loading by default when the component first mounts, right? So we'll do loading, and setLoading, and that'll be useState will be true. And we'll say error and setError = useState and we'll give it a null for now, and probably you could use undefined too.
[00:01:48] So now we have all these pieces, so now we could say, all right, well, and let's assume that this is something they could retrigger. We could have a button to refetch or something like that, so let's at least make this generic enough that we could reuse it. So then we would say, what is it, setLoading any time this call starts out we'll set it to true.
[00:02:07] We'll clear out the previous data. Now, that might change, you might want to do a dynamic reload. If they come back to a page, it might be we're show them a spinner, we keep the old data around. This is, again, depends a lot on the unique pieces of your application and if we're fetching, if there was previously an error, we'll make it go away.
[00:02:24] Now, again, you'd might choose to persist there, this is all up to you, I'm just taking a by base level approach here. All right, well then, if we did get a response, then we have to setLoading as false and we'll setError. Well, we don't have an error at this point.
[00:02:45] If we catch, Then we'll setloading to false and we'll set error to the error. I don't love this, it feels like I am dong a lot manual turning things on and off, right? If only there was a way to just announce that things happened and set up a bunch of rules for what the resulting state should be.
[00:03:23] Anyone have any suggestions cuz I'm at a loss.
>> Is there a hook for that?
>> We could make a hook. I mean, we can build stuff out of it, right? I mean, there's probably a third party hook as well. How do we announce that things happened and figure out the state?
[00:03:36]
>> Dispatch.
>> You dispatch, yeah, you use a producer-
>> Producer.
>> Right, and so now we can say the different parts like, all right, we're gonna start loading. We've gotten the response or there is an error, and that can then trigger all of these flags for us, right?
[00:03:48] And to that point, that becomes a much more reusable pattern, right? Now we can say that we wanna do all of these things, so on and so forth. So, we've got it here, now let's just actually add our loading and error and then we'll round back to that.
[00:04:01] And again, probably we would do something a little bit more complicated, but let's keep it simple for the sake of the parts that actually matter for learning. And we'll [INAUDIBLE] say, all right, if they are loading, go ahead and just show a paragraph tag the says loading, that's fine, right?
[00:04:21] Otherwise, we'll show the set characters, so either show loading or the characters that way we're not showing nothing on the page. And then if there is an error for some reason, we'll say error. This happens to be a class name that I know exists. It say error.message. And so you gotta look for it real fast, we can see that loading, so now we've got that ephemeral state of our application.
[00:04:55] We could choose to show a spinner or something else that goes along the way, we can not show large portions of the UI or only navigate them. But now we have this idea of are we currently fetching the data, do we have it already, is there an error?
[00:05:09] We have all of these kind of things both represented in our state and represented in our UI. Now, if we wanted to, we could pull this out into a custom hook and we'll see some of the trade-offs in a second. So we'll start with pulling it out into a custom hook, and then we'll look at another approach as well.
[00:05:24] And I am not gonna say one is right and one is wrong. I have preferences, but there's not a universal this is the yes and this is the no way. I think some people can argue against me as well. So, yeah, there is a chance that we want to fetch many things from the API, right?
[00:05:43] And we do not want to write this every time, so, yeah, could we pull it out into a hook? We could, right? Again, making it a little bit more reuseable can be tricky, so we'll say usefetch, and that might be the URL that we want. All right, and we'll just say, I'll make one new piece of state cuz the only part that's not super generalizable in here is the fact that we're actually pulling out the characters and setting characters.
[00:06:19] So I don't necessarily wanna take that piece cuz it's not pulling the characters property of the JSON object all the time, it's not, quote, unquote, reusable. So we might offload that either to let them pass in a call back function for how to format the data or let them do it in the component themselves, whatever makes you happier.
[00:06:37] But we'll pull in pretty much the rest of this, And we'll say const, we'll just call response, And setResponse, And that will be useState, I'll paste the rest of that in there. So now we've got just, instead of set characters, it will be setResponse. Same thing here. So now we have this, if we give it a URL, it will figure out how to save some state on the response, the loading, the error, all that stuff.
[00:07:27] Abstract it out of the actual component cuz the component shouldn't care about this stuff, right? It just wants to know the state of the world so it can figure out what to show in this case. Cool, so we could do something like, and now instead of using state, we'll just use, All right, this doesn't return anything yet, so we've gotta do that as well.
[00:07:51] So we'll have it return the response, the loading state, and an error state. All right, and these are set in the state that it's maintaining and it exposes only those things. It hides all this fetching, flipping bits on and off, it doesn't worry about any of that anymore.
[00:08:08] That is maintained solely by this hook, the actual component using it is just like, yeah, yeah, yeah, I need to fetch from endpoint. And it just tells it what it wants to fetch from, and we don't think about the rest, okay?
>> Do you want a d in endpoint?
[00:08:31]
>> I think I do, feels right. Feels like spelling our variables right is probably the right choice. This is why you live code with 15 friends. So here we'll get the response, the loading, and the error. Now, response is gonna have that character stuff, which is a little bit tricky, so we'll probably need to format that a little bit, but we'll deal with that momentarily.
[00:08:56] So response is either going to be null or it's gonna be that object with characters. So I need to just basically check, like, hey, do I have a response? If not, I wanna use that default, and if so, we'll get what we need off of it. So I'll just say, Characters is simply going to be, hey, do you have a response?
[00:09:23] And does that have a characters object? If not, give me an empty array. So if if response is not null, and that object has a characters property, give me that, otherwise give me an empty array. Which is very similar to what we have with the empty array and then we set it, and, again, it's just JavaScript for that.
[00:09:43] So I wrote a lot of code without checking to see page, which fills me with absolute fear. So let's go ahead and see what we got. Lord, it works. I'm gonna refresh that, I don't believe it. All right, so, yes, I would pull this out into another file, this usefetch.
[00:10:01] And now elsewhere in my application, I'm in charge of formatting the data and, to be clear, I'm only passing at endpoint. If I wanted to pass in a second function, which is how to format that response, I could totally do that, right? And then I don't even have to do this inside of the actual component, right?