Loading UI, Suspense, and Streaming in NextJs 13

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in this lesson we're going to talk about suspense and streaming let's start from suspense now if we had to react documentation suspense is a react component that you can use which allows you to display a fallback UI or a fallback until its children have finished loading so typically the children is in async function or it's doing or performing an asynchronous task that's why it's taking up time to load and while it's loading the suspense boundary or your suspense component is going to show a fallback this is typically your loading UI can be a skeleton it can be a spinner while this component is finished loading and once this is completed or the asynchronous task is completed the suspense is going to actually swap the loading UI or the fallback with the actual result of your component now Nexus 13 supports suspense and allows you to add loading UI to your route segments very easy so let's jump into the code and see this in action now building on top of the project that we've been working on in the previous lessons where we added this about page for different route groups and we had some blog posts added a list of all of our blog posts and also individual blog posts here let's see how we can add a loading UI using this suspense boundary that's a feature in react 18 to our project so let's start by our posts now we can have different loading uis or components for each of your route segments and you would create that loading UI by adding a loading.jsx to that specific segment so right now I have added this loading.jsx to my posts segment so everything inside of my post it's now going to add this loading jsx I'm going to tell you how this works behind the scene but for now let's just add a loading skeleton to this and all I'm going to say over here is a section with some paddings and then a container and inside of it let's just add an H2 that says loading okay let me just reload the page and if I now visit this Blog Page you can see that loading text showed up for a second before the actual content of our uh posts page showed up now inside of our all posts page where we are using this get all posts function to fetch all of our posts and then show a list down here I want to actually delay this uh rendering for some time so that we can see this loading better so I'm going to export an async function call weight I'm going to get some milliseconds and all I'm going to do is return and you promise that takes a resolve function and then this is going to call the set timeout function and it's going to call this resolve in that many number of milliseconds this is just going to allow me to delay at the response of an asynchronous task for whatever number of milliseconds that I passed with so let's just go to the get all posts function that we have up top and let's actually evade this weight function and I'm going to pass in 2000 milliseconds or two seconds so now let me just go back to the home page and refresh my application because remember anytime that your page is using a react server component the result of rendering that react server component is now saved in a client-side cache that's why I want to reload so that I'm not using a cache because with the cache it's going to be instant I'm going to actually go ahead and refetch that data again from the server side to for this function to be called and for this delay to happen now if I go to the blog you can see that loading spinner or loading skeleton or whatever loading UI that you want to put in this file uh before I can actually see the content of my page now just like that you can add loading UI to your route segments so anything inside of our posts segment is now going to be wrapped inside of a suspense boundary which allows us to render or show this loading skeleton or loading UI before the content of our segment or page is ready and then it's going to automatically swap the two together now inside of our posts page we have this Dynamic slug segment that's responsible for rendering individual slogs and now because this is also inside of our posts segment it is going to also be wrapped with this loading UI or with the suspense boundary so these components are going to actually use that loading as well now to demonstrate this let's actually go back to our posts and actually add the weight function to this get post spice log function as well so this is going to take a bit longer as well so we can see this in action now let me just go back to my individual blog posts I'm going to comment this generate static prams function out because this is going to instruct next.js to statically generate these Pages at build time if you're running a local development server here but if you have the generated static prompts you won't see this loading UI the way that you should because there you would have a static HTML files coming in there is no asynchronous task of fetching data happening so I need to comment this out before we can actually see this in action let me save this file and go back to the home page let me actually also refresh so that I get rid of the cache so if I go to the all blog posts page now I can see the loading UI before the content or the list of our my blog posts show up and then once I click on one of these blog posts I can actually again see that loading uh skeleton or the loading UI because why individual blog posts or this Dynamic segment is still nested inside of this post segment and I do have this loading file that wraps the content of this forward slash posts in a suspense boundary so anything inside of it all the children and nested layouts inside of it are going to also be wrapped this suspense component or actually use this specific loading UI now in addition to the loading.jsx or this specific file you can add to your route segments you can also wrap any other component that you have which is performing an asynchronous task with suspense component and create your own suspense boundaries let me just close all of this and go to our four slash log page this is the individual blog posts and let's imagine that we want to fetch the view count for each of these blog posts similar to what you can see on blog posts or notes on my site so how do we do this let's actually create a component here inside of our components folder let's call them maybe page views.jsx I'm going to export a page view component here and let's imagine that we want to fetch a page view Counts from rdb or however you're storing this we're going to simulate this by again using that the weight function that we created inside of our lip now again this is going to be you fetching your view Counts from a database from your CMS or however you decide to store it nonetheless we just are simulating this with the use of this fate function now to be able to use a weight inside of this react server component we need to turn it to async so now we're just simulating that you're fetching some page view Counts from our DB let's say we're storing different slugs and different view counts inside of our database or CMS or however or from wherever you're fetching it locally or from a database we are performing in asynchronous task so this page views component is an asynchronous component or is performing an asynchronous task and we want to wrap it with a suspense to actually see that they can use suspense boundaries for our own component uis as well okay so let's just save this and let's say this is going to return to us maybe say views and then it's going to return 100. for now it's just going to just say that statically now if I go back to my page I can maybe come down here and add this page views component we created here it and realistically you would have to pass in your slug over here right and get this log we have this log from this page so you get this log and then inside of your page views you're going to expect an S lock and then maybe here you would have a function that says views maybe equal evading getting a function you can just create these functions get maybe page view and then you would pass in that slug over here to just get that view and then render that view down here if you don't have this we're just going to simulate such a behavior with this weight function that we created here so let's save that going back to this now if I save this as well we should be able to see that views down here if I refresh the page as you can see I have this views let me just give this a little merger bottom as well so if you have them clear from each other so as you can see we have this views down here rendering here now we know that this is an asynchronous function first of all because it's a react server component but more than that it's also performing an asynchronous task inside of it for fetching our view count now what we can do here is we can use react suspense so let's go suspense this is coming from react as you can see this is imported from react up top and all I can do here is wrap this component with this suspense boundary and then I'm going to pass a fallback UI to this let's say I want to say maybe a div that says loading view count and then I'm going to just wrap this so let me just close this so that you can see so all I did over here is that I'm wrapping this asynchronous component with the suspense component I'm passing in a fallback and the fallback is just a div that says loading view count if I refresh this page we may be able to see it so we see this first loading and then see loading view count so first of all that outermost loading UI which belongs to the posts segment was rendered to save your loading that specific blog post and then once that actually rendered this component kicked in this is also using suspense and inside of it if you're fetching some data so we were able to wrap it with our own suspense component to show a fallback UI to show a loading UI while that task is completed and once it is it's actually going to swap the loading UI with the actual content of our component one last thing I want to mention before moving on to streaming is that we can also add loading UI to our route groups so if I go to or about our page you can see we created this route Group which renders a site navigation for our nested pages with the use of this layout Now to create route groups we just have to wrap the name of our folder with parentheses this is not going to affect our route segment or path as you can see here the about page is still accessed at four slash about so the name of this rock group doesn't really matter because it does not affect the segment nonetheless we can also use suspense to add loading UI to our route groups by just adding a loading.jsx file to this route group segment so here let me just export a loading that just returns loading now if I go to my about page and pretend something time consuming is happening here so I'm going to evade that same weight function that we have created and I'm going to wait maybe for three seconds here I'm going to turn this page into an async component so now if I go back and if I refresh my page what's happening is that inside of this about page if you are doing an asynchronous task this about page is inside of our route group and this route group is actually sharing this layout and this loading UI so if I now go to about page you can see this loading skeleton or text is showing before the about page is rendered now all the other pages are going to also share this loading UI as well as that layout as we learned in the previous lesson but for the team and contact because we're not fetching really anything if you're just rendering this div it's near instant but we were able to kind of simulate a more time consuming task happening on the about page now typically these type of pages are static your company Pages team and stuff and whatnot are static but you can imagine the same route segment or a route group for something that's actually really fetching data now these can be different categories for your products so you're fetching different categories you're fetching different products belonging to categories and you're just grouping them all in one route group you can add a loading UI that's going to kick in anytime you're transitioning between different routes so that was suspense and loading UI in Nexus 13 inside the app router we can easily add loading UI to our segment by adding a loading.js or jsx or TS and TSX if you're using typescript to each segment and then that segment is going to use that loading skeleton for all the nested children pages and layouts inside of it you can render any loading UI that you want a spinner a loading skeleton just a text for while the components finish loading and once they do it's going to swap them with the actual content of your components you also learned that behind this scene nextges is actually just wrapping our page components or that segment with a suspense boundary and let me just show you this diagram from the documentation so when you add a loading.js file to your segment for a loading UI what's happening behind the scene is that nexjs is going to wrap your page component inside of this suspense and then it's going to pass whatever you're returning from your loading.js file as the fallback to the suspense component so this is happening automatically behind the scene so you don't have to worry about wrapping your page components or layouts with the suspense you just need to create a loading.js file return whatever loading UI you want from it next choice is going to automatically pass that as the fallback to a suspense component that wraps your whole page inside of your layout now let's also talk about streaming now to understand what streaming is let's talk about server side rendering for a second now anytime that you are requesting a page that's a react server component a request is going to the server and the server is going to fetch the necessary data for that page it's going to then generate the HTML send dhtml CSS and JavaScript to the client side on the client side in the browser next yes is going to first render a non-interactive version of your site it's going to be the HTML CSS non-interactive so for for the user to actually see something and then once the component JavaScript files or react is actually downloaded react is going to kick in and make that component or page Interactive so this is the sequence of a request going to the server the HTML being generated and your page becoming interactive now all of these sequences and steps are blocking and they're time consuming so you won't be able to show anything on the client side in the browser until the data is finished loading on the server and the server has generated the HTML also react cannot hydrate or cannot make your page Interactive unless all the components were until all the components are downloaded on the client side now with the streaming it allows you to send this HTML as it is generated on the server in chunks so it streams the response instead of waiting for the whole thing to be ready and send it to the client side it streams the response in so you can show that UI on the page as they become available and then also react is going to selectively start hydrating these chunks that come in from the server so your page will show up faster this is a perceived boost in the performance because the user can actually see components coming into the page but it's actually beyond the perceived performance it's actually a better performance because now if you're not waiting for the whole data fetching to be finished to get some HTML if you're going to stream the HTML as they become available now imagine that you have a list of content with layouts and sidebar navigations and stuff so you're going to see the static parts of this component that doesn't require any data fetching first so the layout is going to be there on top of that layouts are not going to be re-rendered if the page is uh has been visited before the layout is going to render once and then the result is going to be cached on the client side but for the segments that are changing in this case we're waiting for a data fetching but with the streaming imagine a list of maybe our blog posts or you know different segments and sections inside of your page that are going to be just a stream Dean and shown on the page and then hydrated with react as they come in as opposed to waiting for the whole thing to be finished rendered on the page and then hydrated with react now I haven't found a good way to actually show this in the code to actually see these different components show up on the page but if you look at the diagram that's inside of the Nexus documentation instead of waiting for the whole page to be plugged in so you're dealing with a blank page and then the whole page is going to come from the server with the streaming first of all you have those layouts around and then the result of a streaming response is going to be showing up gradually or as they're being streamed in and streaming actually works with react component models because each component can be considered a chunk so this components can be streamed in separately or as they become available and then further down here it actually explains that react also prioritizes the components that are going to be more important based on the user interaction and the components that don't have any data fetching that will come in first all in all it's going to boost your performance because you're not waiting for that long request or the data fetching that's happening on the server to actually show something to the client so instead of a blank page you're showing UI you're showing maybe your layouts and you're also showing this response streamed from the server as it becomes available and it's also interactive because now react is selectively or partially hydrating different components inside your app as opposed to waiting for the whole page to finish and then hydrate the whole page so that's it for this lesson in the next lesson we're going to talk about error handling and error boundaries inside the app router so see you in the next lesson bye
Info
Channel: Hamed Bahram
Views: 25,575
Rating: undefined out of 5
Keywords:
Id: y9bV8ypChms
Channel Id: undefined
Length: 19min 42sec (1182 seconds)
Published: Sat Jul 15 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.