React Performance

Fallback Content with Suspense

Steve Kinney

Steve Kinney

React Performance

Check out a free preview of the full React Performance course

The "Fallback Content with Suspense" Lesson is part of the full, React Performance course featured in this preview video. Here's what you'd learn in this lesson:

Steve discusses using the React component Suspense to display fallback content until its children have finished loading. A tour of the project notes repo is also provided in this segment.


Transcript from the "Fallback Content with Suspense" Lesson

>> We get into the ones where like this one is, I think, pretty safe and pretty easy. And it's a suspense is a somewhat hard thing to talk about in React, because it's a lot of things and only some of them we have now. So that makes sense.

Yeah. So suspense is this idea of like what do you need to load the initial page? Do you need all the components for every page everywhere in your app always? Probably not like there are, if you pulled out the metrics on the out that you work on, you would likely see that there are some pages that get visited more than others, right?

Like there's probably some deep Admin Tools, preferences, pain that doesn't get visited. So let's load that the initial bundle, right? Like, even like React, this idea of like a synchronous data fetching, like we have ways to do it like we either jam stuff in a use effect and hope for the best.

We use something like Redux saga or something like that, SWR, React query, what have you. There are lots of ways to do it, but React doesn't have a lot of built-in primitives for that. So what suspense is, is a series of APIs. There is suspense data fetching, right?

Where you can say, hey, component, show a loading indicator, because we know that we don't have the data yet, right? And when you get the data, fill it in, right? And some other frameworks have this, React doesn't presently. Suspense data fetching hasn't shipped yet, it's still only certain like next can use it, I believe in remix and stuff like that.

But generally speaking, you unless you're using one of those super opinionated frameworks, you can't really use it. You will eventually one day, but it's still kind of like in a working phase. The only one that is kind of fully in place at this point is the one that fetches components.

So this idea of like, hey, maybe you load the first page first. Should they then go to that second page? Sure, then go pull in more data, right? Because like, it's not just like, the reason that we care about bundle size is not always the download of the bundle.

Like homework assignment that I will give you later is there's like this post called the cost of JavaScript, where like bundle size. Bundles take a long time to download if they're big, right? Turns out that if I was to give you a JavaScript file that was 100 kilobytes, an image that is 100 kilobytes, you know which one takes longer to load?

The JavaScript. Cuz the image, you take the bits, put them on the screen. JavaScript will send you our code, browser, go compile this, right? And then do all the other things, right? And so like there are places where like all of a sudden it becomes more tenable to basically have the ability to like, let's give you what you need to get you up and running, right?

Should you go, we will then progressively give you more and more of the application, which is incredibly powerful idea, right, that we don't have to send you like in the early days here's the entire app. Every time it's anything like download an iOS app, it's like, every three days, we're gonna send you this big wad of JavaScript, parse it and live with it.

So we can progressively be in to load the app. And one thing I love about it Is, and there was a library called, like React, lazy, lazy, load, I forget. But it's basically the same basic idea where you have these suspense boundaries, which are kind of like error boundaries, and you have a fallback, which is like some kind of loading indicator.

And we'll see in fully in a second when I like show it to you in the notes app that we're gonna build or that we're gonna add it to. But you'll see that like for the most part it will show that loading indicator while it waits for the import promise to resolve.

And once the import promise resolves, then it will go show the full thing. So it will automatically build out your entire application, that is basically, at this moment, the only part of suspense that you can use today. And so the rest of it will ideally come at some point or another, but that is the part that we have access to at this moment.

And, but it does give you the ability, it's the amount of work and effort to have it in place. It's one of those things which is almost no real downside, all right? Unless you have for some reason an older infrastructure that can't support it, but should work just using modern web, like the water would import statement and be able to kind of load your app as time goes on, and like works pretty seamlessly.

So let's take a look. I'm gonna switch over to that Notes app. So project notes. Yeah. Cool. And like right now, it doesn't have any of this in place, right? And so, let's just take a quick tour of the app. I'll show it to you real quick. You can see notes.

You can edit them. You can close the editor. You can close the Note. It's an app. That's the thing. What I would love to do is this one we maybe not they start out with no, again, it was slightly contrived, right? They start with nothing there, so we don't necessarily need to show them one, but like, maybe like, they almost never click on edit.

So maybe, we don't pull in this whole edit interface until they go navigate it. And the nice part is step one is, like, load it when you need it, right? Step two is like, there's nothing stopping from kicking off that promise as they hover over the edit button, all right?

Like, you can build, like, increasingly sophisticated implementations of this, right, to kind of have your cake and eat it, too. All right, so if we look at the application, it's got a notes list, it's got a notes view. We can imagine what that is. If we go into the notes view, you can see that it displays a note, great, or empty, right?

And we can have both in place like that. So what I might try to do in this case is like let's do it with, let's do it with this note if they choose to load it. So yeah, we'll put that in place, and what we wanna do is just like load that as time goes on or like, and see the place.

And I have a loading indicator like pre-baked, and ready to go for us. So what we'll do is we'll go, and we'll try to load it as time goes on. So in our note.js We've got this note content, which is like, let's do this like when we need it, right?

And like if it's editing, we show the editing, so on and so forth. So what I wanna do, I guess we'll do it for the editor. I also have this, there is in sleep there is simulate network I'm running locally. It's gonna be instantaneous. All this does is it takes my promise and makes me, wait a second.

It's fake. I'm on my own machine. It'll be too fast, you'll never see it. [COUGH] Cool, and so what we can do here is, so we can bring in lazy from React, that's React out lazy, it's like a buddy memo. It's built in these days and suspense, which is a component, cool.

And now we need that simulate network, which you don't normally need but like, again. And so now, instead of importing editing, right, which we could totally do, what we can do instead is, and this will actually work for other, not just React components. Like, there is an import function that returns a promise that will import files that are ESX modules, right?

Bundler if it's out of date, like if you have an old bundle you've just been like, should totally do that web pack three upgrade one of these days, right? That was a joke. Like, you might have some issues with it, right? But I would like to tell you that the technology exists, right?

I too have had a legacy app and longed for some of these things. I'm there with you. The cool thing that we can do is instead of importing the normal way. We can do and, the lazy part is because of the React pieces and to hook it up with the suspense boundaries, but like import itself I can work, and I even need to get something not a top level at all actually works.

And we say lazy, and then lazy takes something that should ideally return that import promise. So normally, it would look like this, and then we do the same. Call it at this time, okay, edit like that is normally what it would look like. But for me, since that will be instantaneous.

We're gonna slow it down. To see it in place. So that's gonna simulate the fact that it took a second over the network. It's not new. What I showed you in the very beginning is more accurate, right? So now if it's editing, Then in that case we want return, and this is the important part.

You need these suspense boundaries, other like that is predominantly actually just ES not ES6 anymore, I guess right, like it's yes, 2015 is 2022. I think we can modern JavaScript, how about that? Suspense, and you do have to give it the fallback, like what should it show? And that could literally be a paragraph tag with the word loading if you really want, like, doesn't matter.

So we've got this paragraph tag when we say like, I've got a loading indicator that'll show. Claim, I'm happy with it. And when I make something that I'm happy with in CSS, I wanna show it off. And I don't even spell suspense right. Sure to copy that alone, yeah all right, so I can paste it in.

And now you can kind of see a load as I go through. So that should all be in place, we can pop over, now I hit at it. We see the loading indicator that code was not in the original bundle, it was dynamically loaded as I needed it, right?

Again, not doing things as faster than doing things on initial load there's a page, maybe you're never going to edit it no maybe just once you were there, dinner reservation is, right? You can yeah. And there, you can probably think of like the last app that you've played around with or worked on, of places where it's like, this is the main event, these are all the other things.

Again, putting that stuff off is a very, very easy performance win with relatively little downside, right? And so like if you asked me hey I just generally want to work on the performance of my app, should I put memos on everything maybe, or should I like start breaking my app up into pieces, so it doesn't load all that at once, right?

But I made this joke at the very beginning of the workshop. If your app is not on a CDN, like, do that first right? And to be clear, I have worked on apps that were not out. They were just served at a one data center in Chicago. Yes, there's no shame in that sometimes getting the infrastructure in place to do that is a task, right?

Deepest respect I have been there, I have like that Joe was making fun of me, right? And like it's totally worth it. But some of these things become very big wins, right? That we often times overlook, and are worth doing all these cases, and that's the Suspense API that you can use today, all right?

More is coming. There is versions for like, hey, this is data that we haven't loaded yet. And so that way, like we all have done the rigmarole or use libraries. Okay, when I kick off the promise, I'm gonna set loading to true. Then, I'm going to set error to false.

And then when it comes back, I'm gonna then I'm going to set loading to false. And then the data is a true, and I've got a conditional that yes, right? Things that are tedious like that should probably be solved by the framework, but I say that like you're only left with these squishy stuff.

You're also left with a few annoying things, right because they are tricky problems to solve, and to do reliability cost the framework.

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