Current section: Data fetching 29 exercises
lesson

Intro to Data fetching

Loading lesson

Transcript

00:00 Let's talk about data fetching in React. So when you're data fetching in a web application, typically, you're going to use fetch. You'll pass some URL you want to fetch the data from, you get a response from that, and then you can stream that response, or you can get the JSON, whatever that response is.

00:17 There are a couple of things that you typically want to consider before you actually get the data. Like what happens between this fetch call and this await call? There's something going on during this time period, and so we need to think about pending states. What do we show the user while we're waiting for this fetch call to complete?

00:37 Maybe they're on a really slow network connection, or maybe it's a slow backend, or any sort of thing. You don't get to control the network when it comes to anything. You don't get to control the user's network. And so you have to think about pending UI. I don't care how fast your backend is, you need to think about the pending UI.

00:57 The other thing you got to think about is what if response.okay is false? Maybe it's a 404, maybe it's a 500, or a 503. It could be a non-200 response, a non-successful response, and you need to handle those errors. So how do you handle that? Well, in React, the way that you do this

01:16 is with the use hook. The use hook is the same hook that you use to consume context, so context providers. You can use it to consume promises. And what's really interesting about this code right here is that while this is a phone details promise,

01:34 and this is presumably what that resolves to, you don't see any syntax in here that would say, hey, when this resolve, or when this promise resolves, then give me this value. Like, how does this work? We should have an await here, right? Like, what's going on here?

01:51 Well, React doesn't have some sort of magic JavaScript conversion, this isn't gonna get compiled to anything else, this is all just pure JavaScript stuff. What's happening is React has come up with a fancy mechanism to say, hey, if this hasn't resolved yet, then stop execution because we don't have the details yet.

02:10 So think about, like, how could it do that? And there's a little spoiler on the screen right now. The other thing is, this says, if this has resolved, then give me the results so I can return it synchronously. So this component still runs synchronously, it just has a special mechanism for doing different things

02:28 based on whether this promise resolves. And that mechanism is throwing. So this is sort of how it works, like some pseudocode for how this sort of thing works. And we're gonna be building this in this exercise, which will be kind of fun. We're actually building the use hook,

02:45 or at least the promise consumption version of use hook from scratch, so you can really understand how all this works. But I'll walk you through it here really quick. So React is gonna wrap your components in a try-catch. And what it's going to do when you have a use hook is it's gonna say, hey, is this promise resolved?

03:03 It has a mechanism for tracking that. And if it's not, or if it is, then it'll return the resolved result. If it's rejected, then it's gonna throw the reason it was rejected. And if it is not resolved or rejected, it's still in flight, then it's gonna throw the promise. And then in a catch around your component,

03:22 it's going to catch this thrown promise, and it's gonna say, hey, if this error is an instance of a promise, then we're gonna handle that in a special way. We'll say, add a then onto that promise. And if it resolves, then we'll assign the result to what it resolves to. If there's an error, then we'll assign the error to the reason.

03:41 And then we'll re-render the component, and it's gonna call use again. And now the promise is resolved, so we'll return the result. And now, boom, you've got your result. Like I said, we're gonna be building this in this exercise. So this is just like conceptually how it works, certainly not exactly how it works. But hopefully that helps you conceptualize what we're gonna be doing in this exercise.

04:03 So the trick is, now how do we handle this thrown reason or the thrown promise? How do we show the pending UI when this promise is thrown while we're waiting for this then callback to get called? And how do we deal with the reason, the thrown error, if the promise was rejected?

04:24 Well, you use a suspense boundary for the pending UI. So this is a suspense component comes straight from React, and suspense has a fallback prop. So it says, hey, if any of these components are throwing promises, we call that suspending. So this component is suspending because it is throwing a promise.

04:42 Now, I should probably be clear that the fact that it's throwing a promise is an implementation detail of React, and I'm sure that the folks at React would actually prefer that I not tell you that it's throwing promises around because that is an implementation detail. It is possible they could change that somehow. I don't know how, but it's possible

05:02 they could change something in how that works. But the most important thing is, if any of these child components suspend, then it's going to look for the closest suspense boundary and render the fallback instead until its children are all done suspending, and then it will re-render all of those things.

05:21 When it's done suspending, we'll have the result and we'll be able to render this synchronously. For the error case, we're using React Error Boundary. Error boundaries are a built-in feature of React, but they require that you create a class component and stuff and there's some other things to consider when building it. So we use React Error Boundary, it's so nice. And this also has a fallback.

05:41 We're going to be using the fallback component variants of this because it allows us to do a couple extra things. But the idea is very similar to suspense boundaries. If this or any of its children components throws an error or one of its promises rejects, then it will render this fallback instead.

06:01 What I love about this is that it's just so declarative. So you literally just say, hey, I want to get the resolved value of this promise and here's how I handle errors and here's how I handle the pending UI and you're golden. And one other thing that we want to make sure we keep in mind with all of this

06:22 is that you'll notice we have the phone details promise. It's not coming from props. We're not actually like saying fetch directly in here. This is not a thing that you can actually do with the use hook. You cannot just create a promise inside of here.

06:40 And we'll talk about that in the next exercise. But in this exercise, you'll notice that we're actually creating the promise outside of the React component tree and referencing it directly. And there's a very good reason for this that we'll get into later. The other thing I want to call out is that the suspense boundary and error boundary like the error boundary can be used and nested

07:01 in however you like, whatever makes sense for the UI that you're building. And I typically pair the two together pretty often, not always, sometimes you'll find an error boundary without a suspense boundary and vice versa. But often I find them, I'm using them together and when I do, I typically put the error boundary around the suspense boundary

07:22 rather than the other way around. Because if there's an error that happens in the suspense boundary itself, I like this error boundary to be the one to handle it. But again, like this structure can take whatever makes the most sense for your scenario. And that's just part of the beauty of the Decorative API. All right, I think I've talked enough about this.

07:40 We're going to build the use hook in this exercise. Let's get started.