Next.js 13: Data Fetching Strategies

Bookmark
Github

- Introduction

- Prerequisites for the workshop

- Fetching strategies: fundamentals

- Fetching strategies – hands-on: fetch API, cache (static VS dynamic), revalidate, suspense (parallel data fetching)

- Test your build and serve it on Vercel

- Future: Server components VS Client components

- Workshop easter egg (unrelated to the topic, calling out accessibility)

- Wrapping up



Transcription


Hello, everybody. Welcome to our workshop, react Day Berlin, about 9CF13 and data fetching strategies, especially for what concerns the app directory, the new app directory. I'm Alice De Mauro. I'm a sales engineer at Vercel. And sales engineer means basically that I am a solution architect for pre-sales. So basically, I check the architecture of our customers and I see if Vercel is a fit. What is Vercel? If you don't know it, we created and are maintaining it in SGS. We have people working from webpack and we just released TurboPack. We do also have in-house TurboRepo and other tools that might be useful for developers. But in general, if you don't know us, we are the creator of the legendary SGS, which is the framework for react. I'm going to immediately start with what are our prerequisites basically, or what at least I'm going to use for the workshop. Something that I'm going to do pretty often is this movement here. I hope it's not too jarring, but I'm really used to go through my environment like that. What do I have? I have my ID. So I have my terminal and my Visual Studio Code. I do already have some code prepared. The code is going to be at this place. I'm going to actually give you two links. One is going to be the clean code before the workshop basically. I'm going to drop it in the chat. This is public and you can just access it. I simply forked one of our repositories, one of our famous repositories for the playground for an SGS app and just tweaked it for this workshop specifically. What I'm going to do is to actually use the pull request to welcome to our workshop in order to paste or to deploy our changes. All the changes I'm going to make, you're going to see them in this specific GitHub branch. What also I'm going to do is going to be... So I have my Vercel dashboard. I created a pro trial just for this workshop. Why? Because I needed it to have all preview comments enabled for you. If I go on my deployments, I have my preview. My preview is based on the welcome to the workshop branch. So basically here, I'm now going to paste this one. If you are logged in in Vercel, I'm going to paste it here. If you can log in in Vercel, then you are able to actually comment on everything that is on this page. This is going to be our workshop baseline. So for example, I can do like this example, and I'm going to see your comments. If you don't have Vercel yet, consider that I had Obby just, I don't know, yesterday. I think yesterday I had Obby. It's super easy. You just continue with GitHub. You just log in into GitHub and done. Same for GitHub and Bitbucket. And then you can comment on this specific URL. So this URL will also leave after the workshop. So don't worry about eventually things that you forgot to ask or that you don't want to ask now because you want to check things further later on. So please just go here and comment. I'm going to receive them directly on here. Basically, you will see the comments. They're going to see them on the Vercel bot. So I'm going to simply check them here. I think for what concerns what we are going to have more or less ready, it's done. Something else. So what is it all about? Our workshop will be about fetching strategies for the new app directory. I'm going to show you server components, which is basically the default for the new next.js. Client components and how to do it on SUR. Disclaimer is like you did before. Nothing different. Dynamic fetching and how does it work when you opt in, when you opt out and these kind of things. ISR, we provide that out of the box. It's pretty, pretty powerful. If you didn't try it, try it. On-demand ISR, powerful again, very, very powerful. That's probably the longest piece because to set up on the on-demand ISR, it's a little bit more work. Not too much, but still. But that's going to be our most longest probably. And then how streaming works. So how suspense works in general, because that's from react and how it will work together with pages. These are all fetching strategy can be like from the data perspective, they are tightly coupled with the page perspective. So it's also how the pages and the routes are rendered, basically. Just so you know, if you don't know Next or you never used it, we just released Next 13. The app directory is not the only thing that we released, of course. There's going to be also pretty, pretty a lot of others, for example, TurboPack or the image, the font and so on, the scripts all integrated and enhanced. If you don't know or you want to check more, just I pasted there the link. We also have the, I'm going to fetch them right now, the beta. This is specific to the fetching, data fetching strategy. But in general, we do have like the beta docs. If you are logged in in Vercel, you also can comment on them. So if you find something that is not clear, please give us feedback. You know, anything that is useful to enhance our docs, it's always good, especially if you expect it's something that's not there. Please just don't be afraid to paste a comment there. You just click on this little icon and you can just comment and we answer. So if there is some, you know, things that it's not clear on the docs, we do answer questions in general. So back to the code. So I have my IDE here and I'm going to have some code already done because of course, part of the fact I'm very clumsy with my hands, so I tend to do a lot of typos. But apart of that, it's easier, it's faster. It's going to be faster to actually paste the code from something that's already created. I'm going to push this code anyway, so you're going to have it on the GitHub account. First things first. So terminal, my nice terminal. Two things that are very important. Of course, first things first, you have to install everything and I'm going to use yarn. I usually use npm while in my developer careers, I use npm all the time. But these days, I don't know, I like yarn pretty much, so I'm using yarn for now. If you run yarn dev, so these are the two distinct things that are very important. If you use yarn dev, you're going to spin up the dev environment, which is the server side rendering environment with hot reloading. So every time you change something, it's going to be super fast and going to lock a loss. I'm going to show you right now because I have local host here. Unlock a loss is going to always show my changes right away whenever I do any change. Something that we're going to use later on is really, really important to test all our fetching strategy, especially for what concerns the statically generated pages and the static fetching in general, is going to be creating a production build. I'm going to go right away to it because server components is one of these examples where if you have anything that you need to test from the static perspective, you will need to create a production environment and test there because only there you actually have the classic first build and then serve. For now, I'm just going to start right away. So I have my application here. The app directory is the new NestJS directory. I have everything in the package.json, of course, and I do have some groupings. These groupings are not going to be in your routing. They're just meant to tidy, to tidy your URLs. So basically what I did was I have a couple of fallbacks because of the loading pages and so on. Some you tools that I might or might not use, but what is important is our fetching. So from the root directory, localhost slash, we're going to go through all these routing. Every single route is going to be reflected from these names from the folders. This same way, classic NestJS works. So server component is going to be one of my routes. And this is where I'm going to start. I'm going to go to my localhost. So if I click on server component, which is the first one, you see server component is my route. So the name of the folder, exactly the name of the folder, automatically done. From next. Server component. So explanation of server components. They are running the server. They're going to be always automatic. Pcs and layouts are always, always server components. Always, they're going to always be rendered first in the server. I will show you later on client components and how to divide the little pieces. By default, they are steadily generated at build time. And that means that everything is going to be fetched at the time you're going to be fetched from the server. There's not going to be any round trip from the client and the server. So there's not going to be such a thing like, oh, I have the client, I have all my javascript. And then I need the posts of my blog posts, right? And then I have to ask back and forth to the server, no, give me this one, give me that one. So that's not going to happen because everything is in the server, within the server, and the server is going to do all these kind of fetchings without any round trip between client and server. And that's super, super fast, because then they're already built. There is no need to fetch more data. So that's why it reduces waterfalls. Something that I wrote there, and then we will write like that, it's remember to always have a production build disclaimer if you notice that it's statically, it's not statically generated, so it's dynamic. So for some reason, constantly refreshes, and I'm going to show you how to check that. It refreshes, refreshes means all that you're running in dev. So it's just, you know, the dev environment, or something is opting in for dynamic. I will show you dynamic fetching later and what does opt-in for dynamic fetching. Dynamic fetching is where you don't have a cache. Every time somebody asks for your segment or route, segment and route is the same in within SGS, more or less the same. Every time you have a request, it's going to regenerate the page and recalculate everything, which is less optimized, of course, sometimes it's necessary. Okay, so I'm going to start building my server component. What I want to do is want to show posts from just the JSON, classic JSON placeholder, and I'm going to show you how they are going to be just statically generated like that. Server component, I have a dynamic route, the dynamic route is going to take the ID. So it's going to be server component slash the number of the posts, one, two, and so on. In my page, there's just a description, the layout will wrap everything around. I'm not going to explain about layout too much now, because basically it is going to be always the same. What I did here was just creating these little tabs, and these tabs are going to just be the same over and over within all the data fetching strategies. So the layout is what basically is a sort of higher order component, sort of where you just wrap all the children and the children are your pages, and all the other routing children of the other pages, all the other segments. So that's why when I click here, I still see the children, which in reality is what is inside this ID. Consider that page is like your index, basically, is your index.tsx, and layout is the higher order component around and you can, I'm not going to go through it too much, but you can wrap around layouts and layouts and layouts and really have this isolated way to wrap your index pages through all your segments. So I already have this ready. However, I have still to create my index for this slash one slash two blog post. So the first thing that I'm going to do, I'm going to copy paste this piece of code to avoid doing mistakes, also because there's a lot of code. So one of the things I'm going to do is to fetch the title of my data. My data is going to be the post, post number one, blog post number two, and so on. Something I'm going to also do in all pages that I'm going to create, I'm going to show the date of the render. So what happens when you call this function, simply like paste a piece of html, right? And the html is going to be the string of the date where that html is going to be created. This helps to check if it is regenerated every single time or if it's generated only once, which is really useful. And you always have to create a new one because then you can really see, is it being hitting by my request or not? What is about data? So data is something I'm simply fetching from an api. Fetch data is going to be a function and that function is going to be the one that's going to actually really fetching the data from the REST api. It's automatic in pages. So when you have a page component from the naming convention, page.tsxjs and so on, params is going to be automatically taken. And that's basically this ID. When I'm going to have params, params is going to have inside the ID. And I'm going to also show you now when I'm going to have the fetch data function. So I'm going to now create a fetch data function. And the fetch data function is going to ask for the params and inside this ID, this name is going to be the same of this name. So if I would have called it blog post ID, then this one needs to be blog post ID because otherwise it's not going to match the name. This is all automatic, right? So next is going to be this by this one. What fetch data does? It calls fetch. So fetch now in react, classic react. It has been named for being just the native fetch with the duplicate, meaning that you can store these in the cache. So whenever you have a fetch anywhere, that fetch will have the same input of another fetch. Those are not going to be duplicated. So that data is not going to be fetched twice. It's also always going to be fetched once and then the rest is going to just fall back to a cache. That's what the names meant was like fetch now because it's going to be server side. It's going to be saved in a way that is going to always retrieve once rather than multiple times every time you call it. That's why it's better to re, let's say, duplicate the fetch for the same route, for the same URL, api URL in multiple pages, wherever you use it, rather than having it at the top of the pattern, because it doesn't really matter. And it's better to like, you know, isolate your fetching data in general. So in this case, this is the leaf of my tree, because the last route that I'm going to receive, and it's going to be, you know, what, where I'm going to fetch my data. Next did something more. So because next is on top of react, what we did was to enhance fetch with two things, caching strategies and revalidating strategies. So you can write, I will show you later, but you can write the fetch in a way that you decide how cache will work for that single fetch, or how revalidation will work with that single fetch, which is not native to react. So it's in next. What is this going to do is just like going to take the rest, serialize it back to the data, and then I can simply have this data pulled in, something that I need, and I spoke with Tim Nielkens about this just like a couple of days ago. So when I created this specific example, it wouldn't let me, it was a bit more complex than this, so it might have been something else, but it wouldn't let me have it static, it will always be dynamic for some reason. So it was opting in for dynamic. And we discovered that we needed this function, the generated static params. It can be in two ways. You can all generate the static parameters for that route, or basically list them, say, hey, the IDs of this post is going to be the one, two, three, four, right? And for doing that, you can still fetch, right? Again, fetch the posts, all the posts, and then list them here in this way. This needs to be the same name of the params, it needs to be the same name inside these brackets. Or you can just opt for just having them dynamically created as static parameters, because next.js 13 is still in beta. Talking with Tim Nielkens, we were thinking, should this be default? Because theoretically, this should be the default, right? You should just always have static parameters, because this is statically generated. So yeah, the idea here is like, okay, if next.js 15 is still in beta, they're deciding what to do. But consider that if you see that all of a sudden you're opting out of static, for some reason, try this piece of code to see if it will reopt in. Again, I'm going to leave this here just because so you know, if you want to just create all your blog posts, you can, possible, but this is more than enough to opt in static. My code is ready, I'm going to save it, I'm going to switch to my terminal, my terminal just hot reloaded what I just changed, and within my server components, now I have my posts. However, did I say that before? You can see here, right? This is the render. And you can see when I change, it's just right now, it's changing. 2703, 2705, this is dynamic. What also I can check, oh, so big. Okay. Whenever I call, see, there is a 200 here. That means it's not cached. That means that every single time is going to ask, ask, ask again. Why? Because I am in dev mode. So every time you're like, oh, wait, why is not opting for static dev mode? So I'm going to kill everything and let me clear it out and just build and then start. So build will create an actual production build. So everything that's going to be statically generated is going to be static. Everything is still dynamic, all ISR, everything, and then start is going to start. The application, consider that it doesn't have hot reloading, of course. So I will have to kill it again when I will have to go to dev mode. Or when I change something, I always have to kill it again and restart it because it's going to produce the new pages. Done. So I go back to my blog post and then look at this number. It's not changing. Why? Because it's not going to refetch it. It's not going to re-render it. And if I inspect, what you can see, 304, cached, cached, cached, because it's static. So these are server components. By default, they're going to always opt in static. And they're going to always fetch from the server side. So the server is going to do the work, no waterfalls, nothing like that. And to test it, you test the production build. We're going to go in client components because something that, for example, in the beta doc is not there yet, they're just like, hey, go to the SOR and check the SOR or react query, anything to just ask from the client component for your data. In that regard, I wanted, sorry, no Google, no, no, no, hey Google, stop. I should have switched off Google. Sorry, guys. Yeah. Anyways. So client components, when do you use client components versus server components? So that's the question, right? You use client components when you need react or the Windows, everything that's client side to actually work because Windows is not going to be in server components, right? Same way is that process.env is not in client components. So server components, process.env, secrets, all the things that you need to manage from a secure perspective as well, they go in server components. Client components, they are running on the, you know, your computer, on the computer of the user, actually. So user state, user facts, all the changing things that need to be done, they're going to be in client components. How you fetch data? I use the SOR. You can use, you know, so react query and so on. Remember that pages and layouts are never going to be client components. They're always going to be server side rendered. So consider that if you cannot really make them. If you want to have a client component, you need to wrap it around a server component that might be pages because pages is your index. In the future, it will be possible to, instead of using SOR, to use the use hook from react. However, it's still not implemented in S13 because, yeah, it still needs to be, of course, implemented because it's in beta. Always the same. I'm going to do the same. So the code is going to be very, very similar. Let me go to client components. Very, very similar code. I have still the page, which is my index for client component slash, and then I have the idea of the post where I'm going to show you the client component. So in the page, I'm going to still show my regular rendering, which is this one, right? Just the local date that is going to be the render. And then I'm going to have a client component, which I will call blog post. So because page cannot be client, right? I need another component to wrap client around and to make it pure client component. I have to create it, of course. So I'm going to just simply create to make it client component, use client. For now, it gives you an error because it's still not a full-blown react component, but use client will opt you in for client components, which are not server-side managed. Something that I will have to pull in. So my imports, react, of course. Use as var, which is from this library as var we maintain, just for the classic as var. If you already know what it is, it's just a fetching data api. Otherwise, just check it out. It's really, really simple to implement. I will use path name because being a client component, I will not have the parameters, right? So the page, it has the parameters, which is the ID. However, from the client component, I will need to read them out from the path. And then I'm going to use a fetcher and the fetcher is simply, I wrote it here. Let me figure it out what it is here in lib. The fetcher is simply, is really a copy paste from the docs. Plain simple. It's just a typical fetcher that is just resolving the promise from the fetch. So I'm going to create my nice blog post. What is going to return, do it in pieces because then it's a bit easier to check. It's going to simply return loading if there is no data and there is no error and there is data, then the data.title from the blog post, which is the same as before. Nothing really changed there. How am I going to do it? First thing that I'm going to do is retrieve the path name, which blog post am I going to check? I'm going to check the one, the two, which one, which one that's going to come from the ID. And then I'm going to use this one, which looks like this. I'm going to use use path name from next directly. So I have the path, right, of the URL. So, yes, we call your, in this case, the post from the JSON placeholder. So we call your api with the ID and then there is the possibility to have a refresh interval, very similar to ISR, where it's going to basically fetch constantly the new page. The difference between ISR is that this one is similar to polling. So this is really like, no matter what happens, it's going to fetch, fetch, fetch. While ISR, it only fetches if somebody goes on that page. It busts the cache, basically, it's more similar to that rather than fetching, fetching, fetch. This is useful for data that is really in real time, like pure real time data. Okay, I'm going to save. I had my production here running, so I have to kill again. And I will also run my production again. It's not super necessary in this case to run production, but if you're used to that. And then I'm going to see on the page how it's going to go. And then you see the loading. You just saw the loading. Actually, what I can do is to, oh, sorry, wrong link. Network, I can throttle. And if I throttle, last time I tried a very slow one, and I wouldn't suggest it. If I throttle, then you will see the loading because my connection now is theoretically very slow, like a 3G connection or 4G in this case. You're going to actually see how much does it take to pick it up. So it's going to load, it's going to take forever. And then at a certain point, hopefully it's going to fetch my data. Took forever. Don't do, I would not suggest to do GPRS or stuff like that unless it's really necessary because it's really jarring, let's say. Something interesting here is that the page is re-rendering, but also, if you see the network, I'm going to wait a little bit. I think it's 5,000 intervals. So every five seconds it's going to fetch, just like that. It's really polling, the classic one. I use this for a chat. When I was building a chat and then the polling was like every second or something to the database directly to see if there was like any new chat or any something, like notifications, stuff like that. That was client-side and how to do the client-side. Dynamic. Is it dynamic the second one? Let me see. Here we go. Dynamic. Because then we are going to go to ISR. What is dynamic data fetching? So when you have a dynamic page in general, that means that you're opting completely, completely out of cache. Which means that every time somebody requests for that page, that page is always going to come back already re-rendered, already rendered. And it will re-render every time you request it. I can opt out or in cache in a very, very granular way. I'm going to give you this link to the beta docs again. It's called route segment config options. When you have config options or in general, this kind of option for both fetch and the route itself, you can opt in and out from cache and various type of strategies for rendering in a very, very granular way. For example, you can do it only for fetch, but not for the entire route. So potentially you can say, okay, this entire segment or route is going to have cache, but then this specific fetch in this specific page for this specific component is going to be no store. So it's going to be no cache at all, because I know I need it always very, very, very efficient from the dot. No, efficient is not the correct word, but let's say from a refreshing standpoint, efficient. Something that's very useful to know, sometimes you might think, oh, this is going to be all static. Fine. It's going to be super optimized. But then you notice that you do production build and is dynamic. That's because some functions like cookies, headers are inertly dynamic. So they're going to opt you in dynamic automatically without you having to explicitly say it. It might be that's the case. What usually you might want to do then is to maybe put those in the leaf, whatever the leaf might be, the farthest away from everything else. So everything gets like nicely wrapped and nicely re-rendered correctly. I'm going to show you how to do that. Dynamic. So same thing. So page is here, ID page. We're going to do exactly the same. Check the blog post in a dynamic way. The code is really, really similar. I'm going to paste everything because it's so the same. Wait, paste it properly here. It's so the same of the other pages of the regular server side pages that I'm going to just copy paste exactly the same. So same thing, same thing. Fetch data. We have a fetch data function that's going to take the parameter, which is the ID of the blog post. And that one is going to be sent to the JSON placeholder. What is different here is that I have options. These cache no store. Those options, they can just be put for each fetch that you have. Consider that you might want to check how the fallbacks are because sometimes they are, you know, they might, for example, a no store and an actual force cache, they might be in, you know, enemies, let's say they're in contrast. So they cannot be done together at the same level because otherwise, you know, next we'll not know which one to choose. But now I'm just opting out from static. I'm opting forcibly in dynamic. And if I'm going to peel my thing and restart my thing over and over to check my production. Here we go. And I'm going to, I always refresh. It should reload automatically. I just saw it refresh when I peeled because I'm always afraid of the terminal cache. So if I now check the post here, see this production build. So theoretically, it should be just static like the server commands will be. But whenever I click, it will say 36, 38, 40. So if I inspect, it's going to always be 200 every single time. And it's going to always request the entire thing because I opted out. Various things to say, I cannot go over all of this because it's a lot. But check it out, check how you can really granularly set your cache options because you can really do wonders. ISR, very, very fancy next feature and not common to have because it's a very complex strategy to apply from a programming perspective, not from an implementation. So now it's going to be super easy. But in general, you don't find ISR very often in frameworks, which is quite cool to have in the JS. So what are we going to do? Now, static is the best because static, if you don't have any data that really needs dynamics, static is going to be simply a super performant, already generated. Boom, my page is there. Whoa, yay. However, if your page is there and you cannot change it for some reason, maybe you made a typo or the content editor made a typo, that's typical. How do you bust the cache of that page? ISR comes to your help in that regard. Pure ISR is based on time. So there is going to be a revalidation period. For example, I'm going to put, I think, 10 seconds. I wrote 10 seconds. I think what's the code is going to be 10 seconds. And that ISR is going to, every 10 seconds, every request that comes after those 10 seconds is going to be the one busting the cache, basically. So let's say that I wait 10 seconds. One second later, somebody requests that page, cache is busted. So that page is going to automatically be the fresh one. How to implement it? Also fairly easy, also will be the same code because it's easier. I'm going to just paste the same code that we had before. I'm going to have a last rendered to show you when it's going to be rendered. I'm going to have the fetch parameters and that fetch data. Next, revalidate. This is in seconds. Next, revalidate. You just opt in for your fetch data api. And every 10 seconds, it's going to just refetch. I have my static params as well. Make sure that this is static for the same reason of the other page with the discussion I made with Tim Nukins to try to see why it didn't opt in. So I already have my statically generated parameters, which is the blog post one and the blog post two. Let's test it. Then I have to kill. Build all. Every time I have to rebuild because the pages are going to be back again, right? So html is going to be rebuilt. And also next you have this nice thing that you already see. What is server and what is static and what is pure static and which ones are already generated and so on. All right. So post C08. Sorry. Just probably refresh. Sorry. Because now it's 26, 27, 26, 27, 26, 37. See every 10 basically. So 37, 38, 37, 38. At the same time, I'm going to be 47. 48, 49. So you see every 10 seconds, I'm going to request for the page and the cache is going to be busted and that's going to be refreshed and revendored and the fetch is going to be redone. That's why if I move super fast, they're not going to change because the 10 seconds is not going to, it's not finished yet. But as soon as the 10 seconds are gone, that page is going to be, see 16, it's going to be recreated and it's going to send to me. Now, last, almost last but not least. Streaming is really fairly easy, but this is a bit longer. I'm going to try to make it not super slow because of course I'm just minding off time. So on-demand SR. Same of ISR. So you're going to have statically generated pages, but what if instead of every thought, every 10 seconds, I want this to be, want the cache to be busted when I decide? It can be anything. It can be maybe they're old, old pages and you don't want anybody to just go in and bust your cache. Or maybe you want to have a revalidation that's quite long, two days. But then whenever you change a post in a CMS, for example, in a headless CMS, your content editor, maybe they want to immediately like, oh, wait, let's republish immediately because the breaking news are over or the Black Friday is over right now. So I need to immediately bust the cache. A little bit more work, but it's not too much really. It's just a couple of things that we need to know. What I'm going to use here is this really, really cute mock api. So I'm going to paste the code, sorry, the link here. So I just discovered it like three, four days ago. So you can, you have to subscribe to subscribe for free. It's free for now. At least for, you know, basic, basic hobby things. They give you a link, an HPS link, and then you create, you create a resource, which is basically your endpoint. And I created my posts here and you can like add them with the fake data that they create. And if you check the data, you can actually change it. So you can change it at an update. And this is perfect to try on the MondoSR if it works or not. Okay. How to do that? I'm going to close here, close this one. So same, same, we're going to always have the posts and so on. However, now what is going to be different is going to be that, let me paste the same, the same things that is not going to be different. So the things that are not going to be different is going to be like the data.title, the fetch parameters, right? With the parameters as, as the blog posts. And basically the fetch data, which uses a fetch to actually retrieve the blog posts, right? First things first, how am I going to call the, my, my environment? I used a process.env, so basically an environment variable to have my link. So the link that I showed you, the one that's created just for you, that's, that's basically what is going to be there for, for, yeah, for, for having your posts. Slash post is how I called, I don't remember, this one, posts, right? So when you create a new resource, it's going to ask you what is the name of the resource, which is basically the name of your endpoint. And I call it post. So slash post is going to be the endpoint. What is nice, let me see if it shows you here. Yeah, what is nice is going to be that when you have post ID, for example, it's automatically generated that is going to ask for that post. So you don't have to do anything. And then I'm going to just write the typical. The typical is going to be, okay, return the data. So it has like all the stuff, all the jazz, and then just for the sake of being safe, opt-in for static, because again, for what concerns the beta, might be that some things are still not, not opting in even if you want to. What else would I need to do? So in this case, the page is just created, so it's a static page. Nothing fancy. But if I want to bust the cache, I need something else. Namely, it's a webhook. Usually the webhooks are in api from the server side of Next. And I still don't have it. So I'm going to have to create a new folder. And the folder is going to be pages. Pages is the one from basically the other version, right from next.js 12. api is going to still be in pages. So api is just your, you know, server side api, the server, the backend of the frontend, let's say like that. And in my api from pages, so for now, api is still there. Maybe it's going to change later on, but for now, everything you have in pages api is going to stay there. It's not going to change. In api, I will create a new folder. So I'm going to create a new folder. In api, I will create, if I can, hello. Sometimes my edit hides itself. It will create a route. The route will be revalidate. This is an api route. So it's going to pick up this name. So it's going to be slash api slash revalidate. And there I'm going to just copy paste the typical, typical revalidation code, which does the following. Checks the revalidation token. You always need a revalidation token. I have it in my process.env and I have it in my local.env. So it's here. I call it Alice because it's easier. So my revalidation code will be Alice. So if I say, I will show you, but if I say api slash revalidate and then a question mark, and then in my query parameters, so I'm going to be secret is Alice. This is going to check if my process environment validation token has the same. And then if not, it's going to throw an error. Otherwise it's going to bust the cache for that single ID that I'm also going to send through query parameters. So I'm going to send from query parameters both my secret and also the idea of the post that I'm going to bust. And I'm going to see that the other post is still going to be the old one. That's it. I'm going to also now show you how does it work. So how this would just bust the cache. Same, same, same old, same old, kill all. We are on incremental, right? So changing, nothing happens, nothing happens. Refresh, nothing happens. The date is always going to be the same. Same, same, same, right? I'm going to go and change my api. New, updated. I'm going to go back, refresh, nothing happens. Nothing happens, nothing happens, nothing happens because it's cached. Well, what do I want is to revalidate. Then what I'm going to do is do local host and then api. api, here we go. Revalidate secret Alice ID one, right? So now ID one has the cache busted. I'm going to go back, post two, refresh, refresh, refresh, nothing happens. Post one, just revalidated on demand because I called this api. And this api can be called from anywhere, right? It's just a call api. I just called it from the browser. And this one will just stay cached until I don't call the same api on the two. Okay, last but not least, so I let you go. Streaming with suspense. What does it do? For this one, I had to opt in for dynamic because otherwise, of course, when you are on the server side, it's going to just render everything and that's going to just push the already rendered data and then have it static by default. So I had to like opt in for dynamic to actually show you how does it work. Streaming means that each piece of this UI that is going to be wrapped around the suspense boundary from react is going to just stream independently, meaning that your page is not going to be blocked completely for the entire html. It's going to be piece by piece rendered. So if one api takes forever, it doesn't have to block everything else, right? You maybe want the upper funnel to be immediate. And then it doesn't matter if I don't know any lower funnel is going to be problematic or slower for some reason. So you want pages, part of the pages that are immediately interactive up to cart or the first page of a multi-page list of products, stuff like that. How do you do that? So we're going to do the posts now. So we're going to have multiple posts. Streaming. So now it's a little bit different. So I have streaming slash posts. And then here I'm going to stream multiple posts at the same time. Within the page, I'm going to throw tons of errors, of course, because I have some things missing right now, but bear with me. Within the page, I'm going to do this. One suspense for the first post and another suspense separately for the second post. I created a delay because that delay will actually show the rendering. The fact that, hey, I'm streaming this, I'm waiting for this. And this one will be three seconds earlier than the other one. And I'm already going to be able to interact with it without having to wait for the second one. What I will need now, I'm going to just new file. I call it post scale. Don't talk to your six. This is mere UI. I'm not going to explain it. It's really, really basic UI. I stole it from the app playground, as I said, like the rest of some of the code from our own examples for the app playground. I'm going to paste it as soon as I finish this one. And then I'm going to have a button. So another very UI thing. So you don't need to have too much of writing in the nothing. Very, very quickly is a client button. So use client. react. I have a state. So this pure client, right? Because set state is only for the client. Pure state. And this is just going to be clicking the counts, basically. Every time I click, it's counting. This is per post. So I'm going to show you that I can actually click on this one much before the other post is being retrieved. And then last but absolutely not least is going to be the actual post, which is the important one, because it's the one where I have all the nice things. So this post is going to be very similar to the rest. Fetching data. Similar. I have a button. I have the locale time string as before. And I still have to fetch the data. And fetching the data will be exactly the same. Nothing changes here. Same thing code. The only difference is that I added this little piece to fake the delay, because otherwise I wouldn't have any delay in localhost, right? So I'm faking the delay. The delay is personalized per post. So the first post was three seconds. The other one will be six seconds. Done. So what it's going to do is fetching delay. The two posts are going to simply come here, right? Go in the index, which is the page. Start streaming the first one. Start streaming the second one. But the first one is going to come much earlier than the other one because of my fake delay. And now I'm going to show you. I don't need necessarily now the production view, so I can just use yarn dev, the classic yarn dev, because it's going to be dynamic and it's fine. Let's see if the post works. Now it's working and you can see the first one. I can click, click, click, click. It doesn't really matter because the second one came in just a bit later and it won't block the entire post page. We're a little bit out of time. That was it. I'm going to post, post, push this code. So in the GitHub repository, so you can actually see it live. If you have any questions, access the preview comments. I hope it was useful. Yeah, let me know if anything. Thank you very much.
53 min
12 Dec, 2022

Watch more workshops on topic

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career