Advanced Remix

Defer Exercise

Kent C. Dodds

Kent C. Dodds

Professional Trainer
Advanced Remix

Check out a free preview of the full Advanced Remix course

The "Defer Exercise" Lesson is part of the full, Advanced Remix course featured in this preview video. Here's what you'd learn in this lesson:

Students are instructed to implement the defer, Suspense, and Await APIs on the $customerId route to create the best loading experience.


Transcript from the "Defer Exercise" Lesson

>> To open up the ReadMe there, close other editors pull this up and no to dev exercise nine. Come over here, we're on exercise nine now. And login is and Kody loves you, and there we are. We still have a slow customers experience. This is exactly what we just finished with, everything is exactly the same.

So we have the skeleton UI, all of that. And now what we want to solve is I want to make it, so that I can land on this page. And so, we've moved from slow network connection to now the back end is slow. So my network is fine, it's fast.

But we've got a slow back end. So something on the back end is slow. And for some reason, we cannot speed it up. So there are a couple of things that you should do when you've got to slow back end first, make it fast. [LAUGH] So that we spend a lot of time on the front end like D bouncing inputs and whatever to try and make the user experience not so bad.

When we could just ask the back end engineers to index the database or make those requests faster. So make the slow thing fast first, and especially those backend things. So optimize your database queries, add some caching. In our case, we actually totally could, but let's just assume we cannot a caching.

You use a different data source or whatever we're already concurrently loading data with promise dot all we've done all of these things, we cannot make it faster. And there are certainly cases like that, you can't cache it because it's a completely different calculation every time, I call it and it's completely different, can't cache that thing.

I can't optimize the database queries, we've hired the best and they can't make it any faster. It is slow, that's the way it is. There are absolutely cases of slow things that you cannot cache, you cannot make any faster. Or again, everything that you do in software, you're making trade offs with the time that you spend.

So you spend time fixing bugs. Well, now you're making a trade-off on new features. You're working on this particular feature that means you can't work on that feature. You're always deciding what return or what thing you can do with your time to get the better return on investment.

And so maybe it is possible to speed up your back end, but maybe it's just not a priority. It is a sad reality of lots of engineers, at least are lots of my experience in enterprise. Especially is like getting on the priority list of the other teams that I integrate with, it's like really can be hard.

And so, wouldn't it be nice if we had some way to deal with this in a way that gives our users the best experience possible? That is what we are going to be doing. The other thing we have already done, prefetching, the goberspiners, the skeleton UI, we have already done all that.

The next thing that we could do to make this or without this new feature that is coming to remix soon. So that we're gonna be using an experimental version of remix actually here in a sec, but without this new feature, what you would have to do is fetch on the client.

So the reason that this is slow when you show up here is because we're waiting for the loader to run and do all that slow stuff before we can even render any of the HTML. Well, if we render HTML and don't even request the slow stuff, then this response can come back nice and fast.

And so that's what the example is. So if I run node dev example, clients or whatever it is, there we go, client-side-fetching. That's gonna pop up in here, and Kody loves you. And so now if I click on customers, boom, there I am really fast, nice and quick, I get the loading state right away.

If I open it up here, same thing. So that's the experience we're looking for, but there's a big problem with this approach. First, the problem is and I'll show you the implementation too, because it's kind of interesting. So if we go to examples, it is customer ID, let's see.

Client, yeah, there we go. So the way that this works is we have a fetcher and we have a use effect. And the fetcher runs on initial mount, it will load the invoice details for this particular customer. So rather than our loader sending all of the customer info and its invoice details on that initial server render.

We actually add this little feature to our loader to say, hey, if we're actually specifically requesting the invoice details, and let's send that instead. So it's a separate branch of our loader. So we're kind of hijacking our loader for our purposes here, treating our loader kind of like a resource route.

So in any case, this is a slow bid and we do this on the client, we make this request on the client. So this is still running on the server, but we make the request for this when the client hydrates as part of this use effect. And when that finishes, then we come down here, when our fetcher is idle, and we have data, then we'll render all of that all right here.

And it works, and it works fine, this is actually relative to lots of other fetch on the client solutions that I've done in the past. This is actually not all that complicated because you still get like the server code is right there and it's pretty straightforward. However, the user experience is suboptimal.

So first of all ,yeah, I messed that up because I have two versions of the app running, I forgot which port this one's on we are gonna be using this one, okay? You should figure out a way to stay logged in, no matter which app you're on, that would be kind of interesting to challenge yourself.

Okay, so if we look at the network tab, this network tab tells you everything you need to know about the user's experience when they land on your site, they're on any site. So if hit Go, and actually let's do user lens here after you deployed a new version of your site or whatever.

So the cache doesn't work anymore, you have all new stuff. So the first thing that you gonna, that's gonna be a long. Sometimes, for some weird reasons, the document request is long. So there we go we get a pretty quick document request or where's my, way it's kind of hard to show overview, there we go, I just want the first little bit here, just that stuff.

Okay, so that document request is pretty quick and then we start fetching all of the CSS and JavaScript and stuff. And then finally, when the JavaScript hydrates, we can make this network request, that is the long network request right there. Hold on, that's the socket, where's where's our network's request for stuff?

There it is. So this is a request that gets us the customer details and invoice details, all that stuff that's really slow. So this request, yeah, that's right. Sometimes Chrome the network tab will show pull these off of each other. But yes, it wasn't the socket, the socket is still pending.

It's this request that's like super duper long. So the key thing here that I want you to take away from is when this request starts, right? That is the point of all of this. The request starts after the latest JavaScript thing. As soon as that last JavaScript thing finishes and we run all that JavaScript and we hydrate the app.

Now I can start the request as not great, I don't want that, it would be cooler if their request started. I don't know with the document, like it does when we're using our loaders. That's one of the reasons why remix is so fast. It's because all of the, requests for data start as soon as the documents requested, not after the documents done, as soon as it's requested, and so we're missing out on that.

[LAUGH] That's gonna be hard am sure as soon as that JavaScript loads and now we can finally start requesting this. Would be really cool if we could start this request earlier, that's what the defer API that you're about to use enables. So let's move this over, but still not wait for it, we call it promise teleportation, it's pretty cool.

We live with a promise on the server and then on the client we still have that promise, it's not the same promise cuz that's like impossible. But it feels like Get, and it's really cool, so that's what you're gonna be doing is solving that specific problem. And yeah, I describe that in the background here I'll give you an example of what these APIs look like.

And yeah, I have so many things to say about this, but I'll talk about it after our exercise is finished. So you're going to be implementing the defer suspense and await API's on that customer ID route to make this feel really great. I mean, as great as you can make it because you can't speed up the back end, okay?

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now