So, let's continue. Like I mentioned in the intro, the first part, we're actually going to start with React 17 and how we can use suspense inside of React 17 and what benefit it brings to, and then we'll build on top of that when we get to React 18. Now, let's have a look what's going on.
So, this is the basis we need to cover to make sure that we can work with React 18 suspense and suspense list and these kinds of things. Now, with React 17, we got the suspense component and the suspense component will let us suspend some work that's going on. What does this work actually mean in the terms of React? Well, you suspend the rendering of a component or a subtree of components by throwing a promise inside of the render, which is kind of strange. If you think about the throw keyword in JavaScript or TypeScript, you think about errors. You throw an error. But JavaScript will let you throw anything. You can throw a number or a string. React actually uses that by saying, well, we're going to throw a promise when something happens where we can't finish rendering. And that something could be anything, but typically that means you're doing an AJAX request to fetch something from the server. But then again, it could be something completely different, but that's going to be the most common case.
And that something from a server typically is one of two things. It's either you're doing an AJAX request where you're fetching data you want to render. Or the other is you are lazily loading components and you're doing an AJAX request to lazily load some codes so you can render that component. But it hasn't been loaded yet, so it isn't available yet. And then when that promise is thrown, React basically says, okay, we're going to suspend this component or that component subtree, and we're going to wait for that promise to be done. And a promise can be done in one of two ways. It can either just reject, in which case there's an error, or it can resolve, in which case there is success. And if the component subtree is suspended and the promise that suspended it resolves, then react says okay, we're going to render that subtree again and presumably whatever cause it to suspend is done now, so it will render and produce whatever, well, markup DOM elements we want. Potentially it could suspend again to fetch some more data. And in case of an error, React is going to say okay, in that case there is an error, we're going to call into an error boundary or we're going to search for an error boundary and we're going to let it do its thing and if there is no error boundary, we're actually going to kill the application.
Now the application I'm using fetches data. And if we go to source components, and for instance, in users, there is this account details. We can see here that it uses the use SWR hook. So that's a data fetching hook from Vercel called Stale While Revalidate. So it fetches data and refetches data, et cetera. And that's an AJAX request. We've got the traditional code here, handle errors, if there was some error, if we don't have any data yet, we'll show some kind of loading indicator that we're loading and that's actually what shows that spinner. When I refresh, it already had some data in cache. The spinner that shows up here, that's the loading. And if the data is there, then neither of these is gonna render and it's actually gonna go right here. And of course if there is an error, let me just quickly introduce an error by making that URL invalid. So now if I click on the user, we see a spinner and then we see not found because that URL was actually invalid. But let's make it valid again. Well turns out SWR, data fetching library doesn't work with suspense out of the box, but it's really easy to make it do so. In the index.js there is this SWR config, and it has react-context under the hood. And we provide some context on how SWR should work. And it has an option there, suspense, which defaults to false, but we can set that to true. And now it will start using suspense automatically, unless overridden by some other, we could overhead this on an individual case, but we're not doing so. So all of a sudden, all our Ajax requests have switched to suspense. Now this is specific to the way SWR works, but if you're using react query, for instance, it has pretty much the same setup and lots of React libraries for fetching data will do the same. If you're using React lazy to lazy load components, it will automatically loop into suspense. You can't even turn it off, it will always do so. However, now my application is broken. If I make sure that my caches are clear by pressing a 5, I go to users, we get an error. Oops, something went wrong. User list, that was that list of users which showed up before, is being fetched now, but it started using suspense. And that means that we need to have this suspense fallback mechanism. So somewhere I need to add a suspense boundary. And I typically add them at multiple places. But I'll start at the very root. And we'll add some more later on. And we want some fallback so I've got a loading component. And that doesn't quite resolve yet until I've got the insuspense. Now that should resolve the import. So I've got a suspense object. And now if I go back to the root, and now do the same concurrent rendering adventures, we see that it actually fetches its data and it uses suspense there. And if I click on the user, it loads the data. Now you might've noticed there is behavior difference cause originally when I clicked on the user, we would see two spinners here, one for the user details and one for the favorite users. Now, all of a sudden, the whole UI is replaced by one spinner, so not very nice, I would say. We'll actually fix that in a minute because we can do quite a lot with suspense. But if we look at that account details now, it's like, well, are we gonna get errors? No, because with suspense, errors are handled in a different way, so we can get rid of that error. If we don't have data yet, do we need to show a loading indicator? No, because with suspense, that whole mechanism of that throwing a promise kicks in. So we should never actually get here without any data, so we should be able to get rid of that. Now I'm using TypeScript, and I hope you're all TypeScript fans. I am a TypeScript fan and this series React work or front-end work I do with TypeScript or quite a bit of backend work as well. So it actually complains here saying, well, account is an account or undefined. That's because the API here under the hood is using suspense so we kind of know that this account really is an account or a promise is gonna be thrown.
Comments