React Server Components Unleashed: A Deep Dive into Next-Gen Web Development

Rate this content
Bookmark
SlidesGithub

Get ready to supercharge your web development skills with React Server Components! In this immersive, 3-hour workshop, we'll unlock the full potential of this revolutionary technology and explore how it's transforming the way developers build lightning-fast, efficient web applications.


Join us as we delve into the exciting world of React Server Components, which seamlessly blend server-side rendering with client-side interactivity for unparalleled performance and user experience. You'll gain hands-on experience through practical exercises, real-world examples, and expert guidance on how to harness the power of Server Components in your own projects.


Throughout the workshop, we'll cover essential topics, including:


- Understanding the differences between Server and Client Components

- Implementing Server Components to optimize data fetching and reduce JavaScript bundle size

- Integrating Server and Client Components for a seamless user experience

- Strategies for effectively passing data between components and managing state

- Tips and best practices for maximizing the performance benefits of React Server Components


Workshop level: 


No matter your current level of React expertise, this workshop will equip you with the knowledge and tools to take your web development game to new heights. Don't miss this opportunity to stay ahead of the curve and master the cutting-edge technology that's changing the face of web development. Sign up now and unleash the full power of React Server Components!

153 min
26 Oct, 2023

Comments

Sign in or register to post your comment.
  • Sharon Jeffe
    Sharon Jeffe
    Abel & Cole
    Will this workshop be recorded and available online at a later date?

AI Generated Video Summary

React Server Components Unleashed is a workshop that covers the basics, usage, and benefits of React server components. It explores Next.js, caching, suspense, and migrating from Next.js to React server components. The workshop also discusses compatibility with back-end technologies, API key security, caching, and controlling React server components. It highlights the differences between server-side rendering and React server components and provides insights on optimizing data fetching, adding loading components, and using suspense. The workshop concludes with recommendations for developing with React server components and the challenges that may arise.

1. Introduction to React Server Components

Short description:

Welcome to this workshop on React Server Components Unleashed. We'll cover the basics, why they exist, and what they can do. We'll also discuss Next.js, turning client components into server components, caching, embedding server-side code, suspense, rendering components, React server actions, and migrating from Next.js to React server components. The workshop is interactive, with theory and hands-on exercises. It's recommended to type out the code instead of copying and pasting. Prerequisites include a working machine, Node, Git, and NPM.

♪ So welcome, everyone. Welcome to this workshop on React Server Components Unleashed, where we're going to do a deep dive into what they can do. We'll start easy. I'm kind of assuming that most people are familiar with React, are at least somewhat familiar with Next.js, although that's not that important. But they're not really familiar with server components. So we'll go over the basics, why they exist, what they can do and all of that stuff.

So who am I? My name is Maurice de Beyer. I'm based in the Netherlands, freelance developer, instructor. I kind of like working at startups because things are nice and flexible and it's typically a greenfields development which I kind of like. So currently working at Someday which is a FinTech startup in Amsterdam. I'm on Twitter. I've got my website, my email and the QR code there is gonna take you to my website if you're interested, not that there is all that much information. So I'm not gonna go there.

What are we gonna cover this workshop? We're gonna take a look at React server components because after all that's the main topic. And we're gonna talk about why you might care, why you might not care about them. They're new, they're hot and they've got their place, they're really cool. I like them, but it's certainly different. And it's not always applicable. I'll talk some about Next.js because that's the name React server component implies, server, you need a server. React is no longer a purely client-side framework here. So we need a bit more, and there are several options. I just happen to like Next.js a lot. So that's why I chose Next.js. It does mean that sometimes in this workshop, it's kind of fake. Well, what is standard React and what is Next.js specific? I'll try to explain that as much as possible, but the border is some times a bit fuzzy. We'll talk a bit about turning the traditional React client components into React server components, how you do that, what that results in, what changes. We'll take a look at caching and how updates to the underlying data affect React server components, because that's a bit different than with the traditional client side components. We'll look at embedding some server side code. I'm going to query database, but that could be anything that you typically want to do on the server, like, oh, open a file. Maybe do some TCP connection to somewhere else, anything like that, things you typically can't do from the client. So you normally don't do in a React component. Well, all of a sudden now you can at least in a lot of instance. We're going to take a look at suspense and how React server components when they're asynchronously loading data work with that, how you can control updates to the UI. Part of that is streaming when React server components are asynchronous, then the results is actually streamed to the browser. So we'll take a look at that. We'll take a look at something which is confusing. At least I found it quite confusing at start from like, okay, we've got React server components, we've got click React client components, but when does a component actually render where? And as you'll see in a minute, when we talk about React server components, but if you're using them, you're actually not doing anything special there, or maybe you are, but you don't have to. You're doing something special in the React client components to say that those should run on the client, which is well, somewhat strange. And it's sometimes leads to your not really being certain where components are rendered. We're going to take a look at React server actions, which is actually part of the whole React server components movement. It's part of actual Reacts. Initially I thought that it was part of Next, but it's really part of React. And if we have time, but I don't really think we will, we'll take a look at what it takes to migrate from existing Next codes to React server components, but knowing myself, I typically have way too much content to fit because I'm always thinking, well, oh, I should discuss this and I should show that, so we're probably not going to do that, but the slides are there, the exercise is there, so you can always do the exercise yourself. In general, the way the workshop is set up, it's supposed to be interactive, it's a workshop after all, so you have to work for it. I'm gonna, well, first I'm gonna do some theory, but then I'm gonna just do hands-on stuff. I'm gonna show you how to do something, and then you can practice that on the starter repository which I created, and basically you get hands-on exercise of all of those concepts and play around with them. Now, when you do so, you can just copy and paste codes from my repository. Basically, all the exercises I'm doing are in there, so all the finished code is in there. And you can just copy and paste them. However, all you really learn then is some fake concepts and you're an expert at copying and pasting. I'm guessing most of you already are that, most developers are, and it really helps to really type things out, make mistakes, see the error messages pop up and learn that way. So I would recommend doing that. Of course, we need some prerequisites. We need a working machine with all the stuff there. Nothing really special. I'm sure all of you will already have this. That's why I didn't send this out ahead of time. You need some version of Node. I've got Node, what is it? 18.18, which is already no longer the latest version, but anything which is relatively recent will work just fine. It doesn't have to be this. Like if you're on Node 16, that's perfectly fine. No need to worry about it. And even somewhat older versions of that are gonna be perfectly fine. To be honest, I'm not quite sure what the minimum version is. I've not ever run into issues there. You need Git for a bit, but of course, pretty much every developer has Git installed. Again, the version doesn't matter. I've actually got a screenshot of 2.38 and I'm running 2.41, but any version of Git is good enough. You need NPM, but of course, if you've got Node installed, you will have NPM installed. Again, doesn't need to be any of the latest versions.

2. Setting Up the Project and Repository

Short description:

To get started, clone the repository and install the necessary npm packages. The project is a Next.js application with a source folder, app router, components folder, and more. The server component code will run on the server, and we can start the dev server and view the application at localhost:3000.

Any reasonable, recent version will do just fine. You will need a copy of the repository. That's this link at the top here, and let me paste those links in the chat window again. So the repository and the slides. If you click on the repository, it should open the browser, and it does, but on my other screen. All the codes we're going to do in here. I'll show you how I created this in a minute. It's basically a next project. There are two branches here, the main branch, which is all the completed code, so you can find everything you want in here. And there is the start branch, which we'll switch to in a minute, where we have all the starter code we're going to start with.

There is also a link to the slides here, that's the same link as in the slides I shared or in the chat window. If you go there, you'll find... Sorry, you'll find all the slides I'm using. Now that's useful, because if I scroll down a bit, like here for instance, all of these slides where you see an image with code or something similar, those are links. If you click on it, you'll actually get to that page. So that's with all the changes, but if I select another one which has some code, if I scroll down here, not that one, code we're actually going to write, code we're going to write, like here. If I click on that, it takes me to the actual commits, where that is. So if you were looking at the code and wasn't quite sure, or maybe it's longer, you can always just grab it from here. Like I said, I recommend you type things in, but there are some things which are somewhat longer. Let me go here and let me give you a second. You can also take a screen or go to that QR code that will take you to the slides as well. So you'll find the link there. And like I said, I also pasted it in the chat window, the Zoom chat window, so you can find it in there.

Now, I already created the project so you don't have to do so. But just so you know what we're starting with, I created the next application. I did so a while ago, so it's not exactly on the latest version right now, but pretty recent. I pretty much used all the standard options there, TypeScript, because I like TypeScript ESLint, not that we're using it, but it was the default. We're using Tailwind CSS for styling. Not needed for server components, but that's just the default, and I kind of like Tailwind. I'm using the source folder. And the important one is this one. There is a question whether you want to use the app router? Well, if you wanna do server components, that's the one you want to use. If you say no to that question, you would use to old pages folder, and the pages folder works fine for normal React work, but it does not support server components, so the app router supports server components, so that's the one you want to use here. But again, that's the default at the moment. And I used the standard alias. Nothing special there. For UI components, I'm using ShadCN. Again, the details are not important, but I kind of like them. Mostly took the default options there, so those were set up, and then I installed a bunch of those components, just so we can make it look somewhat prettier. Like I said, all the steps we're gonna do are in the repository, and basically every step is a commit. So if I go here, I will have say one step we're gonna work with suspense and React Server components, and if you click on that link, you'll get to this commit, and you'll see exactly what I did. So I added the sleep function to make it a bit slower. I added a loading component here, added a bit more, and you can see exactly what happens. Kind of useful if you get stuck. You'll also see John Luc Picard come by. Anyone who watches Star Trek will be familiar with this, his famous engage. We're not gonna engage warp drive, but we are gonna engage the keyboard. So basically with the exception of this time, all the other times, it's basically the cue for you to go and do whatever I just demoed. I'm gonna use the breakout room feature from Zoom there, so it's kind of like you are there with three or four people together. I prefer to keep them relatively small and you can collaborate on things. So you can open up the mic and camera if you want to and kind of help each other out. If you get stuck, you can always invite me into the breakout room to help you out. So feel free to do so if needed.

Now, the first thing we need to do in order to get started is clone the repository. So I'm going to go to the repository, open up that little dropdown, copy the URL and I'm going to go to a terminal window which I should have open and I'm going to do a git clone of this repository. And I'm going to do a git clone of this repository. Shouldn't take long, it's not a very big one. I'll cd into that and once I'm there I'm going to do an npm install. That should download all the required npm packages and I'm using a database here. Nothing terribly difficult but the database will be created as a post install step so you should see some messages about that. I'm using Prisma so there we see Prisma migrating you should see a message like this with the migration and your database is now in sync and Prisma's actually been updated since but that's perfectly fine. There should be no errors in here. That should all be fine. Let me open up Visual Studio code for the project here. The project is like I said, relatively standard Next.js application, there is a source folder I'm using the app router so there is an app folder here which contains the different pages. There is a components folder which contains a bunch of components we're going to use. There is some more stuff here, lib, some utilities and the Prisma stuff and a server component with some codes which should run on the server but doesn't quite yet. Now let me actually start this. Yes, so we've got to dev server running and then I can go to local host port 3000, where does it go? Let's just type it in then, local host port 3000 and we should see the application show up. There it is.

3. Exploring Movie Features and Troubleshooting

Short description:

You can navigate to the movies page, view movie details, make changes, add movies to the shopping cart, and check out. There is a message about exporting metadata, but it can be commented out. Ensure the application is running on localhost:3000. Some users may encounter errors related to metadata export, but it can be resolved by commenting it out. The issue may be caused by different package versions installed via YARN or PNPM.

So react London logo. There isn't a lot to it, but you can go to the movies page. You should see movies, each with their own card, a small list of movies. You can go to movie details. You'll see the details from those movies. You can make a change to them, submit. You can add one or more movies to shopping cart and then do a checkout and type in some name. If I can type in my own name, some account number, and let me actually open up the console window. If I press OK. Actually, I was expecting a message here, but it doesn't, which is because I'm still on the main branch. I should switch to the CRHR start branch. Let me refresh this. Think it stopped running now. Now it's running again. There we are again. Wait. Why is it not? It did add them to cart, so let's do a check out. And you see that I did a check out for the Godfather and Shoreshank redemption and I actually added that twice. So kind of works. That should have been done on the server, which it initially did. But we'll fix it later. You can filter movies by genre, like just to have some functionality to risk this genre's option here, which will show a list. But that's for that's using the old Pages API. Well, if we get around to it, we'll convert that to use the App Router and react server components and there is this little utility page. To investigate what happens on the server and what happens on the clients. So. There is a message from Varun. I got an error when going to localhost port 3000. You are attempting to export metadata from a component that's marked as use client. Hmm. I wasn't aware I had metadata in there. But. I'm not sure I got the same message. There is this metadata block which works fine for me, but the person apparently not for everyone. So if you comment this out, I'm pretty sure that will solve that issue. It's not important for the workshop, so feel free to delete it or comment it out. Interesting that it's causing an error though, because I'm not seeing any errors there. So that was the NPM install I did. Check out the Start branch. Don't forget that, like I did initially. I started the application. In this case, it's from the console window. Doesn't really matter whether it's the console window or if you do it from Visual Studio Code like I did. It should work either way. And then you should be able to navigate to localhost p0rt3000 and have the application running, and just check whether that's the case and whether it actually works. And I'm guessing a number of you have already done that. But there's Jean-Luc Picard. Let me go and open up the breakout room so everyone can do that. Okay, that's everyone back. Everyone has the application up and running. Or if you got stuck, please let me know. So I'm getting your attempting to export metadata. So that was this thing you had that commented out Because in that case, there is no more metadata. That's the only place that's being used. And that's in this file. The layout.tsx in the source.app folder. Interesting that it's cause an error because I'm not seeing an error. So that's fixed it. Okay, good. Yeah, Richard didn't have that problem. Neither did I. So I'm kind of curious to what's causing that. Maybe a difference in some version. But if everyone used NPM to install the packages, then there is a package.log file. So we should all be using exactly the same NPM packages. Unless other people were using YARN or PNPM, which might've installed later versions of Next. I'll investigate that later. Anyway, it's not a big problem. For the rest, I'm not expecting a big issue. So Svetlana says I was using YARN and that was fine.

4. Understanding React Server Components

Short description:

React server components are optional and completely different from server-side rendering. In an original React application, the server and client render everything. With React server components, green components execute only on the server, while red components can render on both server and client. Server components are typically non-interactive, while client components handle interactivity. React server components allow for asymmetrical behavior and simplify asynchronous loading. The code for server components is not sent to the browser.

So, next, let me check what version I am using. I've got 13.4.19. I've got 13.4.19. So yes, that's exactly the version I was expecting. Let's hope we don't get more issues because of that. And if we do, we'll fix them.

So, before we continue with the next exercise, I'm first going to do some theory about what React server components are and why you might care about them and when you might not care about them. So traditionally, React is client-side framework or actually, that's what slightly upsets the React team because they always say it's not a framework, it's a library. So framework, library, whatever you want to say, it's purely client-side. You might run things on the server because we have server-side rendering from day one. But that was always optional. And in fact, React server components are optional as well. You can still do React purely as a client-side framework, but React server components are completely different from server-side rendering.

If we look at an original React application, we've got the server here in green and the client in red. We see everything is rendered on the client. The server traditionally doesn't play any active role in this, you could just use a completely static file server. In fact, I've served React applications for blob storage in Azure or AWS, no capabilities other than serving files and that works just fine, everything happens on the client. Now we could do server side rendering, nothing new. That's been around since day one of React but that basically means that we render all our components on the server, so now we do need some capabilities on the server, all of that is turned into a big HTML string, we could either use react-dom.renderToString or renderToString to make it slightly faster for the client. We would ship all of the HTML generated from that to the client but we would also ship all the codes that was used to do that to the client and then the client would render everything. Again, it would basically start with root application and it would render all the components again and then recreate the HTML and then update the DOM if there were any differences. Now the server wouldn't actually execute all codes. There would be things like useEffect which would never fire on the server, that would only fire on the client. But for the most part everything just happens twice. With React server components that's no longer the case. The green components here like Application, Navigation, MovieLists are server components. Those execute on the server, but only on the server. They don't execute on the clients. The code's needed for them, it doesn't ship to the client so it couldn't even execute them. The two red components, RateMovie and movieEditor, they are client components and if you were using SSR, so Server-Side Rendering, they would render on the server as well and then later on the client again, but if you're not using server rendering, then they would only render on the client.

Now, what kind of components would you render on the server and on the clients? Typically, the ones that don't require any interactivity are going to render as server components. So we'll have an application navigation with menu options, maybe a movie list, which loads a bunch of movies from the database and renders those. Well, there is no interactivity there, no click handlers, no use effects, no state which is being updated. All of those could be server components. They don't have to be, but they can be. Anything which is interactive, like a movie editor, where you only have inputs, probably validation behavior, so you don't save an empty movie. Things like the Wait Movie Component, where you'll have a thumbs up and thumbs down button, or something like that. Or maybe you can give it a number of stars. First interactivity there, you listen to mouse events or something like that. All of those are Client Components. None of that can happen on the server. And part of the reasoning there is that a server component runners on the server. Of course the user isn't on the server, the user is on the client machine with the browser. So it can't react to any events. So you can't update state there, it can't have side effects there. It's kind of like you render the application. You render the markup or the virtual DOM object and all of that shipped to the client and from the client that can't be updated. You can re-render the page, the whole page, but you can't say, well, I've got a new movie. The movie list here in the middle. This one, will be updated and we'll re-render that page with a different list movies. Now in that case, we just have to re-render the page and it will pick up the new movie from the database and render all the movie cards.

Now, one of the cool things with React Server components is they can be asymmetrical. But traditional React components are synchronous. You call them with props. They render some or JSX, which basically boils down to, it returns an object describing what the component should look like. The virtual Dom objects. And that's it. And that could be state change as a result of effect or clicks or something like that. And they will re-render, but it's always we render them and they just return, and that's it. If we've got asynchronous behavior, we start using the useEffect hook, useEffect fires sometimes later. If it needs to re-render the application, it will need to do something like a setStates, and that triggers React into re-rendering the application. You can't do a fetch there for instance, and just say, await to fetch. You can do that as part of a useEffect, but not as part of the rendering of the application itself. Well, with React server components, you can do that. So loading something asynchronous becomes much simpler. No longer a component with some state, which defaults to say an empty list of movies, a useEffect, which starts a fetch, and when the fetch is done, it does a set state to update that list of movies, and the component rerendering. No, you just create an async component, and in there you just do an await fetch movies, and you continue with those movies. And for that matter, because they run on the server, it doesn't need to be a fetch. You could just go directly using Prisma or something else to the database, which is pretty cool. Also, what's really cool is the code is never sent to the browser.

5. Using React Server Components for SSR

Short description:

React server components allow for asymmetrical behavior and simplify asynchronous loading. Server components are typically non-interactive, while client components handle interactivity. React server components can be asynchronous and involve async actions. TypeScript 5.1 started supporting Async components. Next.js is a recommended option for using React server components. Other options include Shopify Hydrogen and Remix 3. Astro React components are not considered server components. React server components are beneficial for static websites with infrequently changing content, allowing for faster rendering and caching.

So you've got some, say, an API key to use for some backend server. Well, if it's executed from the client, that API key is leaked to the browser. A savvy user, a hacker for instance, will find that key if they're looking for it and they can use it. If it stays on the server, they can't see it. It's never sent to the actual client. Because a lot of code isn't sent to the client, bundle sizes are smaller as well.

Now, one thing to be slightly careful with, if you're using TypeScript like we are right now, you have to use a relatively recent version of TypeScript, TypeScript 5.1 started supporting Async components. Before that TypeScript had a pretty strict notation of what a React component was, how JSX worked, and a component would always have to return the result of JSX render. It would not allow it to return a promise of that, even though it works quite well. Since 5.1 they actually check the React typings to see what the possible result values are instead of having it hard-coded, and it works perfectly well.

Here's an example of a React Server component. So note this is an Async function. React Server component doesn't need to be Async, but it can be. And in here I'm saying, okay, go and load the data, in this case I'm using Prisma to directly go to the database, find all the movie genres in there, do a find many, I can specify an order by here, et cetera, and that returns a promise of genres so I can await it, and I've got them, and I can then pass them into some other component to render, or render everything here if I wanted to. In this case the genres actually contain interactivity so I don't want to render them here but I could just start returning a bunch of divs and L.I. elements and list elements, stuff like that, whatever you want. In that respect it is just a normal component.

So a question, if the server component involves an async action like in this example, does it need to be async? Yes, it does. If I would leave out the async keywords then TypeScript, or even JavaScript itself would start complaining saying well you can't use the await keyword inside of a function which is not asynchronous. And if you don't do that, I guess theoretically you could do an await and then use the dot then chain things on so it looks in the end still return the JSX but that's not very easy to read and I'm not even sure if it would work. Never tried that. So if we've got react server components they're not actually all that different because I could leave out the async keyword and awaiting anything and it would still be a React Server component. What's a React Client component? Because we need to have components which are only from the client. Well, typically that means they have some interactivity but then, you know, have some interactivity but React is not gonna check whether you have a click handler there or something, that would be very hard. So you kind of have to tell React from this component is a client component. You do that by putting a little string on the first line just put the string use Client there and that tells React, this is Client side components. That doesn't actually mean that every component that does not have to use Client is a server component. It might be a server component. It might also be rendered as a client components. I'll come back to that later because that is a bit confusing and you kind of have to look at the whole stack of components. But anytime you use Clients in a component and it has to be right at the top of the file you turn that component and all of its children into Client components. They render on the Client in the browser so all the code required for that is ships to the browser just like we always had. If you're using SSR, which Next does, then they will also be executed on the server as part of the server-side rendering but that's not required. If you're not using Next.js but something else without server-side rendering or even Next.js, if you're using dynamic with SSR suppressed, then they will not render on the server only on the Client.

The general selector on the previous slide, that's a question from Katlyn, is a server code, a server component, like by itself, you can't really tell, it's a matter of how it's being used but the fact that it's async and it uses Prisma here to directly access the database means that it can only run on the server but there is no use server statement or something like that at the top. There is a new server, I'll come back to that later but it means something different. I'll also come back to how you can enforce that this can only be used on a server and that you don't accidentally use it as a client component. But it is a little confusing at least, I found it confusing at first that we're talking about react server components but we annotate client components that they're not server components which is maybe a bit strange.

A bit about next.js and the app router. As I mentioned, react server components, the name already implies it means we need server capabilities. It's not just static files which can be rendered with server, for the markup and then HTML page and everything happens on the client. That's still perfectly valid. There is no need to use react server components. If you've got an application which is very dynamic, you're probably better off using just client-side components, and that's perfectly fine. But if you want to use reactor for components, then you need server capabilities. There are a couple of different options. I'm using next.js, which I think is the best option out there. Part of the reason is there kind of on the leading edge. And that's at least to some degree is because a number of the core React team members actually left Facebook or Meta as you should say, and joined Vercell to work on next.js. So they're kind of leading things from inside of next.js. Other option is apparently from what I read is Shopify Hydrogen. I've never used that myself. But I'm told that will do React Server components. I would have expected Remix 2 to do React Server components as well because that shipped relatively recent, but it doesn't yet. They've announced, they will be adding that to Remix 3 when things have stabilized a bit more. Which makes sense, because there are some rough edges. I guess we could say that metadata thing was a rough edge. I am running React Server components in production and I am seeing some errors in Sentry, which I think, hmm, I didn't see those before. So there are some rough edges. The application actually works fine, but it's like I've got playwright end-to-end tests running inside of a GitHub action and I'll see some errors pop up from those playwright tests which don't actually produce errors when I run the application for real.

A question, would Astro React components be considered server components? I am not 100% sure, but I think not. Astro does a lot of server-side rendering, but it kind of uses React on the server and ships the HTML. And as we'll see later, server components don't actually ship the HTML, they ship, sorry about that, the virtual DOM objects being returned when the component renders. So another question, in short, are no significant benefits or views in React server components if there are no server actions? Luke said it's beneficial for monolithic structures, No, I wouldn't quite say that. There is some proof to that. I would say React server components are very beneficial if you've got a more static website. Suppose you've got a website, let's say a blog, well, those blog entries are not gonna change very frequently. Rendering those on the server, where you might have to do a lot of fancy rendering, maybe you've got things in markup so you need to transform the markup into HTML. Doing that on the server is gonna be faster. You can cache the results for different users.

6. React Server Components and Back-end Compatibility

Short description:

React server components can work with other back-end technologies like Spring and Java. Fetching data more often from the server than from the clients can provide performance benefits. One interesting option is Waku, a new framework built around server components. Another option is the React server components demo, which provides a demo of how React server components work.

You don't have to ship that library which actually does the markup to React conversions to the client. So anything like that would be beneficial. A very dynamic application. You'll find there is a lot of interactivity. So you're gonna make a lot of components, client-side components anyway.

Can we make React server components work with other back-end text like Spring, Java, et cetera? Yes, you can. No problem whatsoever. It just means you fetch data more often from the server than from the clients. And that might seem like a small benefit but your internet or your connection between two servers is typically a lot faster than the connection from a client to a server. So you'll probably get a lot of benefits just for loading all the data there and only sending the relevance information to the actual clients. Like if you think of a REST server which returns a movie object which has a hundred fields, lots of details. You probably need only 20 of those to render a movie card or maybe even less. Well, you might get all of that from the server and then ignore most of it. It's much faster to ignore that on the server and on the client.

Couple of other options. There was one interesting one called Waku. Which is a completely new framework built around server components. I've not used that myself, but it's created by Dashi Kato. The developer who's behind Sustant and several other of those small focused state management libraries. He typically does a very good job and it's certainly interesting to look at. And all the code is out there and it's a lot easier to understand the code in Waks than the codes in Next.js. Also interesting to look at, although certainly not meant as production code is the React server components demo, the React theme did. That's another repository out here, which explains Sorry about that, but it's a bit, my throat is getting a bit irritated. So this is a demo they actually created a couple of years ago for React conference and it has been updated with the way React server components are supposed to work. It's really demo code, so relatively easy to understand as well. Wakku might be interesting for production in the future, I wouldn't do so right now, React server components demo certainly isn't.

7. Understanding React Server Components

Short description:

React server components differ from server-side rendering. JSX is transpiled to API calls, and the result is a JSON-like object. React server components are rendered on the server and sent as a payload to the client. The client reconciles the virtual DOM objects and updates the browser. Asynchronous components can suspend on the server and continue on the client. Server-side computation reduces client load. Localization decisions can be made based on headers. The choice of server or client processing is up to the developer. Code bundling for server and client components requires additional complexity.

Now, I already mentioned this a few times, but React server components differ completely from server side rendering. With server side rendering, you render everything on the server and then ship HTML to the browser and you ship all the code to the browser and it executes again. With React server components, we render them on the server and we don't ship the code to the browser, so they never re-execute there. But we also don't ship the results as HTML to the browser. We might if we combine it with server side rendering, but pure React server components doesn't do that.

In fact, if you look at React under the hood, you write the React components, you see JSX there, well, that JSX is turned into an API call when it's transpiled, and that actually turns into React.createElement calls. And the first argument is the component to render, the second is the attributes, and the third is all the children. The result of React.createElement is a JSON-like object, there is a __type there which will tell you what to render, there are children there, there are props there, you can use that. And in fact, React always used that, when we called render, we would get those objects back. And then React would start a reconciliation phase where it would say, well, I've got a description of what you want, rendered in the browser. I've got the actual DOM objects, I'm going to compare the two, that's a reconciliation phase, and I'm gonna apply the differences, maybe add some elements, maybe remove some elements, maybe add or change some attributes, like class names in your HTML.

Now what React Server Components does is it says I'm gonna render that React Server Component on the server. I'm gonna take that JSON-like object, and I'm gonna send that to the client. The client will receive those, it will still go through the same reconciliation phase, except instead of calling that render and creating that JSON payload itself, it will just take the JSON payload from the server and inject that. So on the client it's still the same reconciliation process where it takes all those virtual DOM objects, partly created in the browser, partly created on the server, mixes all of those together in the right tree, uses reconciliation to update the actual DOM elements in the browser. So in reality, from that perspective, it's not that different.

So any time they talk about that payload being sent from the server to the client, it's a React Server Component payload, the one mentioned right here. Sometimes you'll actually get to see that. I'll show that a bit later. It's not all that important that you know what it looks like, but it's kind of useful to see things. One of the benefits of doing that is that can be asynchronous. So a component on the server, as I mentioned before, can be asynchronous. Well, that React Server Component payload is streamed to the client. So a component can suspend there, use the normal suspense boundaries while it's being loaded on the server. And then when rendering is finished on the server, it's streamed to the client and the client continues and unblocks that suspense boundary.

Question, is there a computational advantage for the client still then? Yes, there is, because everything that happens in your render, so in your normal component, doesn't have to happen. You want to calculate prime numbers in there, for instance. If it's a server component, that prime number is going to be computed on the server. Only the result will be shipped to the client. And if you've got a really high-end server, that's going to be much, much faster than having that code shipped to say, some low-end mobile phone and computing those prime numbers there. Now, of course, you're not going to compute prime numbers, but you're probably going to do something else. And maybe load a long list of movies from a database, filter them based on some criteria, transform them. So there's still a considerable advantage to doing that. Even just the fact that you can directly access the database and not go through some REST API or GraphQL API first.

Another question. So with RSE, there's still a two-step process. The basic difference, there is no reconciliation. Well, there is the reconciliation on the client. Not on the server. So on the server, it just renders and produces that virtual DOM structure that's streamed to the client, I should say. And on the client, the normal reconciliation works as it has before. I'm sure there will be some tweaks to that internal code. I've never actually looked at the internals there, but it's basically the same process as before.

Before I continue, one more question. Can localization decisions be made as well? For example, rendering dates based on localization. Yes, if you know the locale and you can, for instance, because you can access all the headers from the request. You can check what the preferred language is and use that. No problem there. And another question. Is this too much processing for the server? Does requiring a more powerful hardware than normal? That's really up to you. You get to decide what happens on the client and what on the server. If you think it's better in some cases to spread the load to all the clients connecting, then just slap on a used client to the component that does that and it's going to happen on the client, not on the server. So you really get to choose where you want to do whatever you need to do.

So a bit about code bundling. It does make the whole build process quite a bit more complex because we've got code which executes on the server, pretty much all the server components, and if you're using SSR, all the client components as well. Then on the client, we don't want the server components. We only want the client components. So we have to build different packages for that, different bundles. Fortunately, we don't have to worry about that ourselves, that's taken care of by Next and Webpack, et cetera, but it does require additional complexity there. This React Server DOM Webpack package, that's part of React itself. It actually scans for those use client directives and decides, OK, this should be part of the client to bundle and all the components it renders from there will be added there, and it's also checked what's not needed. So we leave that in a bigger server bundle.

Now, let's get back to some hands-on code because that was quite a bit of theory and behind the scenes stuff. So let's create a React client component into a server component. Please, I've got a nice application here, where is it? Here. But right now, all of this is just pretty much a traditional client-based application. The list of movies rendered here in these cards are rendered to client-side, none of that happens, server-side. So there is no interactivity in rendering a list of movies. There is a bit in the cards here, like there is an Add to Card, and there is a Details button. The Details button is just a link, so that would be perfectly fine with React server components.

8. Turning Page Component into a Server Component

Short description:

To turn this into a server component, remove the useClient statement and eliminate code that uses useState, useEffect, and interactive DOM events. Fix compile errors and ensure the movie cart has a click handler. Update the fetch URL to be relative for server-side execution. The server-side loading of movies reduces unnecessary data loading and improves performance. Use an environment variable to configure the fetch URL based on the hosting environment. Be aware of additional considerations when using server components.

It would just render an anchor tag and do the normal browser behavior. But the Add to Card is actually a button with a click handler, so that's will need to remain on the client. But for the rest, we can kind of simplify this component. So let's go to this Page Component.

In the app router, all the pages start with some kind of page.tsx. So here you can see I'm using app router. I've got movies-page.tsx. That means if the browser goes to the root of the application slash movies, then it's going to render this page.tsx. As you can see here, I've got a used client statement and that makes this a client component. And it does some data fetching here. So if I go back to the browser and I open up the Network tab, we should see that request come by. Let's just filter out the fetch request. We see here that there is a fetch request for movies and it loads all the data. And for instance, we can see there is a bit of data here for a movie, but that's popularity. I think it's showing the backdrop so that poster path, for instance, and the release date, they're not needed. They're still loaded, but completely unused.

Now, in order to turn this into a server components, we can remove that useClient. Now, if I go back, I'll get lots of compile errors. Basically, for a server component, you can't use useState. You can't use useEffect. You can't use say a click handler, any of those interactive DOM events. None of that works. If I look at this code, it's kind of the standard React client component. I first start with an empty list of movies. I've got to use the fact which actually fetches those movies. And then over here, kind of loop over them. Well, we can't use useState, useEffect. So let's get rid of those. We don't need any of this. We can't do any of that. So all of that goes. Now it's kind of complaining about using a wait here. So we turned this into an async function. And no more compile time errors here. It's still not quite going to work. Let me save this first, And actually it does need, does have one compile error. So let's fix that. Movie array. So the movie's type is actually typed as a movie. But if I go back to the browser, we still see there are errors.

Now the errors are inside of the shopping cart. So there are a few more things. Well, where does that shopping cart come from? It comes from, as we can see here, from the movie cart. And we've already seen in the UI that the movie cart has a button there with it, presumably a click handler, but there would be little point in a button without a click handler. So now the easiest way around that is to say, well, let's go to that movie cart and let's make this a client component. And if I check down here, indeed we see there is a button and it has the on click handler. So that would be one issue. So now we get another error, Fail to parse URL slash API slash movies. The reason this is failing is we're doing this fetch here, right here. And we're not passing in any video effects So it's taking this parts as a URL to fetch from. But in the browser a relative URL like this is perfectly fine. It will basically take whatever location you're at and combine that with a relative URL and continue. But now this is executing on the server and the server doesn't have the concept of relative URL. So we kind of have to say, well, this becomes a relative URL and we start this with HTTP localhost with an O and we're running on port 3000. And now it works again. So I can refresh and everything is fine. If I go back to the DevTools though and I check, we can see there is no longer any movies being loaded. Of course they are loaded, but they're loaded on the server, not the client. So we never get to see any of that stuff here. So, it's nice. We're not loading more data than actually needed. We're doing a fetch request, but that's on the server. So it has a fast connection. Of course this goes to the local host. So it's always going to be fast. It does mean that this parts, has to be configurable. I typically use an environment variable to set that up, that's for local development that defaults to local host, and on the server it is updated with whatever URL that server is actually running on. How you set that up depends on how you host things, but I typically or at least often use for cell for my next applications and there isn't default environment variable there available with the current host, so easy to set up. But it is something which does show up now. By the way something else, which is not really apparent, but it's good to be aware of.

QnA

Exploring Fetch and Answering Questions

Short description:

This fetch is augmented by Next and has additional capabilities, including default caching. It deduplicates fetch requests, so be aware of that. Changes were made to the movies page, adding useClient to the movieCards and moviesDetailsPage. The moviesIdPage uses useClient and renders a movie form. The component is simplified by removing unnecessary loading UI. Browser native APIs can be accessed in client components, while server components can't. Fetching from your own API may not be necessary, and data access code can be moved into the component itself. React server components can have any other components as clients, while client components can only have other client components as children. Rsc can be used to hide implementations like encryption or black box functionality.

This fetch looks like the standard fetch you get in the browser or for that matter, in Node these days. In both cases it's not. It's a fetch which is augmented by Next. There's nothing to do with React Server components, but it's the way Next works. They give you a fetch with some additional capabilities, it behaves for the most part as the standard fetch, except there is some default caching here. If you see queries that don't execute or execute differently than you expect, keep that in mind.

The most important thing to be aware of with fetch is it tries to dedupplicate fetch requests so if you're doing a fetch request and you not seeing it, it's probably because it next thinks it was already done. You can control that, and I'll show you some more about documentation there. Like I said, not important for server side rendering, but it's one of those things you might run into if you start using next here.

So that's a change I made to the movies page. Remember all of these are links, so just click on this to get to the actual change. The useClient I added to the movieCards. I also did the moviesDetailsPage here, so let's actually do that as well. It's a small change. Here's the moviesIdPage here. We'll use useClient. This renders a movie form. So that's an interactive form, so that needs to be a client side component. Let's see, get rid of the useEffect, useState. Just to show it doesn't make a difference, I'm using a Lambda function here with fc, et cetera, versus a normal function in the other page, really doesn't make a difference. So let's get rid of all of this, and pass this as a movie object. Let's make sure this actually works. So if I go to details, it should work, but it doesn't. This should be async. And that function declaration should be gone as well. And the same thing with localhost here. Is it working now? No, fetch failed. I think there is a typo in local. All right. Local host, that should work better. There it is. So that works and this component, I can actually make a bit simple because now I'm saying, if the movie hasn't loaded yet, I will render some other UI, but by the time this finishes, it will always have loaded. So I can actually remove that and say, well, just run with, there is no loading UI there, not needed. Do it actually re-render. Yeah. So, simplifies the component a bit. I will show you later how to set up loading UIs and things like that. The useClient I added to the movie form because that's an interactive component. So it obviously needs to run on the client.

And before we start this, there were a few more questions. Can we rely on browser native APIs? Though, I mean you, I'm guessing you mean this with client components. Like, in the client component, you can access any browser APIs you want. On the server component, of course, you can't because you're rendering it in the server. But then, like using a form to submit a post request on the server, yes, even with the server components, like if you render a form there and that form gets posted, it contains the normal browser behavior and that will be sent back to the server. So set up some action there and the server will catch that.

So another question, presumably in reality, you don't want to fetch from your own API, marshall and marshall.content. You'd want to do the same database query and code that's in the API controller. Indeed, you're completely correct. Like this approach might be valid in some cases, but if you're just gonna call to yourself, to your own backends, then I wouldn't do this. And in one of the next steps, we'll actually change that. And instead of calling our own REST API, I'm just gonna move to data access code into the component itself and short circuit that. If you're doing more of a say, this rebuted architecture where you have a different backend, but still one you own, you might still use a fetch to go there. So it's not that fetch always goes away. But in a lot of cases, I would not use fetch. I would just go to the database. Depends a bit on the application setup.

Another question, if you are already explaining this a bit, but can have RFC components, have client components as children, are there rules for this? Yes, they can. I didn't go into this in any detail yet. I will more, but the simple, quick answer is a react server component can have any other components as clients. Both server and client components. A client components can only have other client components as children. But it doesn't need to be explicitly annotated as a client. So if you've got a component which doesn't say anything about use client use server, it could just render anyway. It could render as a client component if it's the child of another react client component.

Another question in your example earlier, the movie API call is not shown in network tab because it was called using Rsc. Yes, that's correct. Could this mean Rsc is also used to hide implementations such as encryption or black box functionality? Yes, very much so. Suppose, I mean here and I wanna add some kind of API keys. So I might do something like API key is 123 or something. This API is completely hidden from the end user.

API Key Security and MovieDB Integration

Short description:

API keys used in client components can be visible in the browser, posing a security risk. The movies data is obtained from the MovieDB API using a valid API key. Searching for API keys on Google can result in leaked keys.

They'll never see it because this code doesn't ship to the browser, it doesn't execute there. And with current client components, I see this quite a lot and I actually do this myself sometimes. Those API keys are leaked into the browser and they are visible from there. So someone could potentially use them. I get the movies data I use I get from the MovieDB, a pretty useful side which have an API. I've got a valid API key so I can use it. But if you ever need to search for an API key, just Google for some codes, which development with the keyword API key, and you'll get a dozen API keys on the first page. So they leak all the time this way, they don't.

Resolving Import Issue and Updating Movie Details

Short description:

There was an issue with resolving the main object movie import. The MPM install may have caused an error. You can rebuild the project using the Prisma reset command or regenerate the types with the Prisma generate command. Removing the UseClient from certain files caused a new use state error, which can be resolved by adding UseClient to the movie cart component. However, this change broke the application, as the updates made to the movie details were not reflected in the movies list. A hard refresh is required to see the updated information.

Let's see, other questions. My main object movie import is not resolving. I think I missed some step to generate the main object from Prisma. That could have happened if your MPM installed through an error. Do I still have that open? Yes, I do. Like when you did the MPM install, you see as part of the post install, you see... I think that worked correctly. Let me see. I mean, it's not a big deal. Like you don't have to hold the whole work because it still compiles in next and all that. Yeah, and you can actually rebuild it if you... If you... there is this Prisma reset command. Let me zoom in a bit. You're at the bottom. And if you run that, it will recreate your database, run the migrations again, basically regenerate. Or if you only want to regenerate the types, you can use the Prisma generate command to do that. Okay, let me give that a try. Yeah, like I say, it's no big deal. Yeah, good. Okay, so let's go and do this. Okay, that's everyone back. So no issues there, I hope. For me, I can't get back on this because I got a new use state error on generateSelector.tsx. I removed the UseClient from movies.page.tsx and then I removed it from layout.tsx. Oh, don't remove it from layout.tsx yet. We will later, but right now that takes quite a few more changes. Okay, and so when I remove from page.tsx in the movies folder, I see the error of the UsedData in the shopping cart.tsx? Yes, that's correct, but if you add the UseClient here in the movie cart, then that error should go away. Where, sorry? In the movie? In the movie cart. Oh, cart, okay. So we'll put the movie cart here and the UseClient where you need to add a UseClient, sorry. Yeah, you add that to the movie cart component, the one I've got. Oh, okay, okay, okay. So I add here. UseClient. That should take care of that hook error. I need to add it in the main line of the page, right? Yeah, it has to be right at the top of the page. You can have comments above it, but no code. Okay. So let's try again. Yeah, now it's working. Yeah, yeah. Okay, good. Okay, thank you. Okay, so let's continue. This, we made this change, but we actually sort of broke the application. Let me show you something which broke. Where is it? Yeah, let me go back to home and make sure everything is refresh and up to date. Right now, if I go to the movies list and I click on details and I change the Godfather to say, part one, cause it was the first part. I click submit. It says here at the bottom, success movie, move updated, that should be movie. That should be movie. So, my bad. But now if I go back to movies, it still says the Godfather. It does not include part one. If I open up a new tab, local host port 3000 again, go to movies. It says the Godfather, so I'm not seeing the update. Go to details here. Still seeing the old one. Except when I hit refresh. I did control-5 a hard refresh just now. Then it's actually updated. And if I go to movies, still not updated. It still shows the old one. And the same if I go to a different tab. If I go to details, I'll see the part one with the different part. If I go to movies, I don't. Let's start up a different browser. Firefox. I'll go to localhost ports 3000 and not on HTTPS.

Caching and Controlling React Server Components

Short description:

The router cache is a client-side cache, while the server full route cache is completely controllable. The client-side router cache is not quite sophisticated and caches things for 30 seconds or five minutes. The server-side caches are configurable, and the client cache can be invalidated, although it's all or nothing. To make a page dynamic, the 'dynamic' setting can be exported from a page or a 'revalidate' option can be exported with a time value. After making these changes, the page should update immediately or within 30 seconds due to cache timeouts. To update the client-side, the router can be imported from Next and the 'useRouter' hook can be used.

You see the same application. Go to movies. I see the Godfather, Not The Godfather, part one. And on details we do get part one. So what's going on? Let's get rid of this one. This one is enough. This isn't React server components specific. This is next specific, but next is very aggressive about caching. It does so to make things faster, which makes a lot of sense. But in a scenario like this with data changing. It needs a bit of help.

Basically, if you follow this link, you get to the next documentation and it explains all about caching. And you can see from the index here, there's quite a bit of information. In the overview, you can see there are four different caching layers in place. There is requests memoization, which is on a request, which actually works with the fetch, the fact that fetch is patched by next or wrapped by next, I should say. Behaves slightly different. There are two caches, a data cache and a full router cache, which are on the server. And in our case, it's the full router cache, which is playing in 2D here. And the reason I didn't see any update until I hit ctrl F5 was also because of this, the router cache, which is a client-side cache. So there are lots of different caches involved.

Now, the full router cache passes, sorry, catches, caches, let me say it correctly, HTML in the React server component payload. And it does so on the server. So those caches are shared between different browsers. And by default, it has some heuristics about what's dynamic, what's not, but it's typically default to thinking stuff is not dynamic. So it's kind of says, well, I can just serve the same results over and over again, which is why on the movies, this overview page, we don't get that, the Godfather part one. It just keeps showing the Godfather. The router cache is a client-side thing. So you can actually get things which would be updated on the server, but still not on the clients.

Now, the server full route cache is completely controllable. The client-sides, route cache is also a bit controllable, but a bit less. With the route, the server route cache, we can set something to be dynamic, which means it will just rerender every time it's requested. We can give it a specific time-out, like rerender this every minute, or every hour, or every day. And we can also invalidate those caches where we tell next, okay, any cache for this URL is now invalid. Please re-render it on the next request. The client-side router cache is not quite sophisticated. It will basically cache things for, I think, 30 seconds. It actually says so somewhere in here. The router clash. Duration. So if it's a dynamic page, it does so for 30 seconds, but if it thinks it's a static page, it will actually cache things for five minutes. Those two settings are not configurable. The server-side caches are, but with the client cache, you can tell it to invalidate but that's like all or nothing. It will invalidate everything. So, let's go, affix first the server-side, and if we look at the server payload parts, there is a setting here, where is it? There is this setting dynamic, which we can export from a page, and that will tell Next.js that this page is dynamic, or we can export a revalidate option, where the revalidate value is the time I believe in seconds, that's data is considered valid. I want it dynamic, so I'm just gonna use the dynamic option. So in the Movies page, I'm gonna end an export. Cons of dynamic is force dynamic. In the Movies page, so the details page editor, I'm gonna do the same. So let's see what happens now. Let me make sure everything is refreshed. So we go and rename this to Godfather Part 2. I submit, I actually submitted it twice, but it doesn't matter. I go to the page manager, I go to the movies, we still really don't see this change. But now if I start up Firefox again, so on a different browser, localhost port 3,000, without the HTTPS. And here I go to movies, now you see that we do get to Godfather Part 2. If I wait a bit here, it's now a dynamic page. So if I wait 30 seconds, then this will update because after 30 seconds, the cache will be timed out and it will go to the server. We want that a bit more immediate. And also over here, when we add it right now, it's updated, but suppose I updated again. The updates was complete, but it still says Part 2 here until I actually refresh it. So in order to do that, we can go to the Movie Editor, so the Movie Form. In here is the SaveMovie function, which we call, which does the actual post to the server and updates things. Well, here we can tell the browser stack. So we have client stack to update. So what we need to do is import the router from Next. Is useRouter. Now, if I resolve this, you'll find two different options here. Let me zoom in a bit to make this real. You can see, it can add an import from Next slash router and from Next slash navigation. Anytime you work with the app router, you should use the bottom one.

Next Navigation and Cache Refreshing

Short description:

Next navigation and cache refreshing. After saving movies, the router can be told to refresh and update all client-side caches. The changes made to the pages and MovieForm are explained. There is a question about cache validation when deploying changes on Prod, which can be done using the RevalidatePath API. By calling RevalidatePath with a slash, all pages underneath will be invalidated and regenerated with the next request.

So, Next navigation. Next slash router is for the pages folder. It has a slightly different API and that's not the one we want. So, let's resolve this from Next router. And now, after we've saved movies. I can tell the router to refresh. So, refresh all client-side caches. So, now if I go back to the clients like the Godfather, part three, here. I go to details, we see part three. But now if I turn this into part four, we get the success updated message. But this is also immediately updated. And if I move to movies overview, we see part four here as well. So we kind of need both changes. Now, using the Surfer Functions, we can actually make this nicer and slightly more integrated. And I'll show you how to do that later. But that's still an experimental API. So for now this is kind of the way around the user interface, but for now, this is kind of the way to do that. So here's the change I made to the two pages. And here's the change I made to the MovieForm. Let's see, there was a new question. How would you validate the cache when we have some changes deployment done on Prod and would like to update the client. Adding force dynamic won't be a good choice, I'll have to add it to every page. Now indeed, what you can do is there is an API. We're not using it in this workshop, but it's called RevalidatePath. See, I can show it in the documentation briefly. On demand validation. This one. We can use RevalidatePath on the server and there's an associated RevalidateTag, if you do RevalidatePath with just a slash to root, any page underneath that will be invalidated as well, so it's recursive. So what you could do is create an API call with a webhook, call that and in that API call just to RevalidatePath and it will basically tell NextOK invalidate all the server side caches and all pages will be regenerated with the next request. Okay. That was the other force dynamic I added.

Simplifying Data Fetching and Selective Loading

Short description:

We can execute server-side code in components, making the code simpler and more direct. The Route Handler becomes unnecessary. We can order movies by different criteria without the need for additional options or paging. Over-fetching can be reduced by selectively loading only the necessary data. By using a select statement, we can choose which properties to load, eliminating the need to load all data. This simplifies the code and reduces unnecessary fetches.

So let's go and do this. So this subject already came up a few times but instead of doing fetches from pages with server components and querying an REST API we're hosting ourselves. Can't we do that simpler? And I already said, yes, we can. It means it's faster but there are some additional benefits as well because we can make things simpler and easier on ourselves. So, if I look at, let's say, let's start with the movies page. Here, I'm doing the fetch. Well, if I go to the actual components, where is it? Sorry, not the component, but the route. We can see that under the hoot it uses Prisma to, based on whether to Resizor or not, basically loads data that way, return that as JSON. Well, if we can execute server side code in the components, can't we just execute all of this? And indeed, we can, so let's copy this, go to the pages. I could actually remove that whole function there, but I'll just leave it for the moment. Resolve, Prisma, and that one as well. And now, instead of doing that fetch and all that stuff with local host, which I would need to deal with, I can do Cat Movies. Pass in to genre, which is String or Undefined, which I need to change here. So, we'll say it will accept a String or Undefined instead of String or Null. And that's an Async function. So we'll call it using await. And now this is directly typed as a movie object or an array of movie objects with the correct shape. Our code is simpler. And this whole Route Handler here doesn't do anything anymore. We can just get rid of it. Delete it. The end result in the browser, is it right here? Should be exactly the same. So if I refresh, go to Movies, we load exactly the same data, exactly the same way. But now it's a bit more direct. And one of the places that's beneficial is say in this order. Because I want the most popular movie at the top. And I actually added that in my REST API. But for REST API, it doesn't make a lot of sense to order movies by vote average. I might order them by ID or title by default. But if I wanted something of vote average I would have to add a specific option to say, well, I want them ordered slightly different, and I typically need to include paging there as well because the list would be much longer. In this case, all of that is a lot simpler. We can do exactly the same here. Again, we're doing a fetch. That goes to this route, it uses this GetMovie. So let's copy this. Again, resolve that Prisma import and get rid of this fetch and then... Wait, GetMovie passing in the ID. Now it does come up with that the movie is possibly null because we're doing a findFirst. And that might make sense in the REST API where you wanna be explicit, but here we can just say, well, findFirst or throw. So if the movie doesn't exist, just throw an error. Problem solved, movie is no longer a movie or null. It's always a movie now. Otherwise none of this code would solve. We might wanna check here with a tryCatch and return and not found or something like that in real life. But for now I'm good with this. So let's make sure that still works. Like we can get to the Godfather, we can get to another movie. And if I type in some invalid ID, then it's Roche and of course. It would be handled slightly nicer, but it is an exception as it should be. So here are the changes I made for this. I'm actually gonna do a bit more, so let's skip Jean-Luc Picard for a moment. Because I'm still doing a bunch of over-fetching. If I look at the code for the movie page, where is it there? I'm basically over here in find me the complete movie objects ordered by, but I don't bother about the fields. And if I look at the movie cards here, what do I need? Well, I need the title, the vote average and count. I need the description, the backdrop path. That's it. Well, the ID, but nothing more than that. So, I don't actually need to load all the data in there. So, what I could do is I could add a select, and I say, well, what do I want to add? So, I would want the ID for instance. Okay. Now I automatically get a compile error saying that not all of the properties are needed. And if I look at that movie, I can see, well, it's actually typed as, I need these and these properties, like the ID title, overview, vector path, et cetera. So, I can say, well, I'm just gonna load those, none of the others. So I've got the ID. Let's actually do this slightly simpler. That wasn't simpler. Why is it not valid yet? Because I'm editing the wrong thing. That doesn't help. This is the one I need to edit. Why am I selecting the wrong thing all the time? And it is still, I'm doing the same again.

Optimizing Data Fetching and Suspense

Short description:

To prevent overfetching, only the required data is fetched. The used client should be used in the movie cart, not the shopping cart. The button in the movie card, which uses the shopping cart, should be on the client. The main object problem needs to be enabled with the Prisma plugin. Next.js allows for short-circuiting suspense in asynchronous pages. Components can be made slower by adding a sleep function. The UI is not updated until after the specified delay. Cached pages load instantly, while non-cached pages have a delay.

Sorry about that. My editing skills leave a bit to be desired. Let's not try to be smart about Visual Studio functionality. There as well. So now I've got the right fields to include there. So now I'm only loading the data which is really required. And I can add the same here. And in fact, I'm going to take this out for a moment so I can share it. I will add it here and... what is happening here... Yep, and make sure this is typed. This should satisfy... Prisma.select and that should be the movie select. And if you're wondering why are you satisfied? I don't want to change the type of the select because that actually affects the shape. Prisma thinks I select things. Now if I have a typo in here, like if I add a 2, it will give me a compile error here because that doesn't exist. And if I remove this, it will give me a compile error down here saying the movie I'm passing in doesn't have the right shape. So satisfies is pretty useful for that. So this prevents all the overfetching. I only fetch the data I actually need and I get a faster application again. So that's basically what I did in here. And different orders, different paging, etc all can be localized just as you need. So let's go and do this. I see there are a few questions in the chat window, so let's address those. One from Lucas, I'm getting an error attempting to use the used shopping cart from the server but it's on the client because it contains state and everything. So indeed as a reply below that was yes, you need to use used client but not in the shopping cart itself. It actually needs to be in the movie cart. Let me open up that movie cart. This movie cart needs to have the used client if you don't you'll get that error. So now you'll see this error about the shopping carts and the used client. The reason it needs to be here is it uses the used shopping cart in part but also because it uses this onClick handler for the button. As soon as you start using event handlers like that it's a client side thing, the user can't click on the button on the server so this can only work if it's available on the client. So all of this has to be on the client. Now in this case it's the whole component. If I was doing this as a more realistic application and looking at this card let's actually look in the UI, it's like, for the title, the vote averages, the image, the text, etc. even this link don't need to be on client at all, those can be rendered as a react server component. It's only this button which has an add to cart click handler, which uses that shopping cart, that's the part that needs to be on the client. So with that in mind, I would probably refactor this button out with the add movie, which is a result of that new shopping cart, create a client component for just that and this movie card would remain a server component itself. But for now we'll keep the whole movie cart as client. So the main object problem needs to be enabled with the Prisma plugin. Right. And not a question about that movie cart, but that's what we're taking care of now. So. Let's continue with the next bit and that's about suspending pages and loading them. Again, this is a bit of Next.js specific thing, suspense works with every React Server component, and I'll show you another example later where we'll use it with the standard suspense boundaries. But in the case of a asynchronous page with Next.js, you can actually short circuit that a bit. It still uses suspense under the hood, but you don't actually have to use that yourself. You can add a loading.tsx and just render another component when your page loads. So let's artificially make our components a bit slow. So let's go to the movies page and let's make this loading a bit slower. I've got a little utility function in here. Sleep and I can tell it to wait a specific amount of time. Say let's wait two and a half seconds. Awaits. Resolve this, and let's do the same in the movies details page. And of course that needs to resolve as well. So now if I refresh the application to make sure nothing is cached, if I go to movies, it's loading. But we don't actually see anything happen for two and a half seconds. The UI is not updated at all. Then if I'm on a movie, I click details. Again, nothing appears to happen for two and a half seconds. A little bit of traffic, nothing happens. And only then do we navigate anywhere. Everything that's already loaded is in the cache. So if I go back to movies, that's instant. If I go back to The Godfather, that's instant. Back to movies, instant. If we go to another movie, that's not in the cache. Again, we have to wait that two and a half seconds. Feedback there would be nice.

Adding a Loading Component and Using Suspense

Short description:

Next.js makes it easy to add a loading component. By creating a loading component, we can display a spinner while asynchronous code is resolving. The suspense boundary is lifted when the code resolves, and the UI is displayed. The loading component can be added at the root or specific pages. It's important to note that the suspense boundary is present even if not visible. This is achieved using suspense.

And Next makes this really easy. So that's just adding to sleep. We can add a loading component, and I'm just gonna copy this because there's no point in actually typing that in. And I've copied a bit too much, I think. Just this part. So next to the page for the movies, I'm going to create a loading dot TSX. Paste this component in here. Component itself could be anything, but this one just renders a spinning SVG. So, let's go back to the root of the application. Now, if I go to movies, we see a nice spinner, and when the actual asynchronous code resolves, the suspense boundary is lifted and we get the UI. Same if I go to details, we see the spinner. If I get back to movies, it's loaded from cache. So, no needs to actually do that again. If I make an edit, Godfather part five, and now if I click on movies, the cache has been cleared. So, it needs to render again. So, it's low, and we see that same loading indicator. You can add just one at the root if you want, the way Next.js works is it basically will look for a loading next to the page, so I'm looking at the movies list. So, if I'm on the movies details page, there is no loading there. It will go up to the level and check if there's one loading there. If not, it will check one level up, et cetera. So, you can just create one at the root. It will just cascade down to all the pages. Or you can create more specific ones for each page. I might say I want a different one for the movies, loading movie data, something like this. Now, if I click on a movie, we just see loading movie data and not the Spanner. And if I refresh, we do the same, but on the list, we get the Spanner. You don't really see the suspense boundary here, but it is there. This is using suspense. We'll see a more explicit explicit suspense example a bit later. Here, different pages. So please go and do this.

React Server Components: Streaming and Payload

Short description:

React server components use streaming and have a payload. There are Revalidate Path and Revalidate Tag APIs for invalidating and regenerating pages. The payload for React server component streaming resembles JSON. The DevTools show network requests and responses for React server components. The layout and certain components can't be rendered on the server. Some components need to be client components due to state and API calls. Combining client and server components requires understanding. Async/await is not supported in client components. Components need to be reverted to client components for compatibility. Components can be influenced by rendering on client or server.

Now, I mentioned several times that React server components use streaming and that React server component payload. So just a bit more about that. It's not a big deal. It's more an internal thing, but it's still kind of nice to know. I mentioned the Revalidate Path. There is also a Revalidate Tag API you can do on the server. Revalidate Path is basically any page under the path you revalidate is invalidated and will be regenerated. Revalidate Tag you could use if you start tagging individual data elements. Not really used that yet, but it's more granular where you can say, well, a specific page for a specific movie, for instance, or sorry, specific movie, for instance, has been invalidated and now any movie or any page with depends on that movie is going to be re-rendered. The actual payload for the React Sherwin component's streaming looks a bit like this. You kind of see different snippets here. It kind of looks like JSON, but it's basically not exactly JSON but similar. It's on different lines so it can be streamed as a different part a singularly. In Chrome, it's a little hard to see Chrome doesn't really show you, but in Firefox, I can actually show this. Let me refresh this and then if I open up the DevTools and say I go to the details for movie. And I look at the response. You can see the response here for what happened, and they're actually two different React server component pages. You can kind of recognize them in the DevTools here. You see the request and you see an underscore RSE is with some hash code in there. Those are the network request for React server components. And in the response, you can kind of see, not terribly important, but just so you know. Now you can make pretty much any React server component, and we've got a site layout and currently that's not a React server component yet, but that's also one of these things. Like, if I look at the application, but this layout has the nav bar in there, which actually has a list of journals to filter things, which for some reason doesn't even work anymore. Interesting. I think I broke that somehow, or is it just the wrong selection? Ah, it actually works, but it doesn't exactly reload very fast. The reason we didn't see the spinner, by the way, is because it's just the query parameter changing, so Next thinks we're still on the same page, so it doesn't need to show that loading state. So something to keep in mind. I personally think that's a bug in Next, but we'll see if that changes. Now right now, as I said, the layout is a server component, sorry a client component, but we kind of want this as a server component. Now there is a bunch of stuff in here, a shopping cart provider and the header, a toaster, and of course the page we want to render there. And not all of those can be rendered on the server. In fact, if I go back now, we immediately get an error, like there is a genre selector, which is a new state there. So that must be a client component and that's actually part of the site header, which has a navbar. And somewhere down here is that genre selector. So I can go in here and say, well, that should be a client component. And if I try that, I'll see the same about the shopping cart. Where is that? Over here so let's make this a client component. And then, we still have an error for that main navigation, which I already had open. So we gotta make this a client component as well. And then it's back to working. Let's actually get rid of those sleeps because it's a little annoying now that it's so slow. That's here and there, we don't need those. So now things load a bit faster. So turning most of this into a server component is relatively easy. Although in reality most of it still renders on the client. And one of the things that renders on the client is if I look in the shopping cart, no sorry not the shopping cart, the genre selector. This still has some new states, it actually needs a bit of state, but it still does a fetch that goes back to, where is my API? Yes, here. So it actually goes and calls this API, gets data over reserver, gets data over REServer, and in reality, it would be much nicer if we could just do that inside this component, but that's a little tricky. And in order to do that, we kind of need to understand how we can combine Clients and Server Components. Because I can't just turn this into a Server Component, let's quickly try. Let's grab this. And say the genres, where are they? Over there. Get rid of this. Make this async. And get rid of the useClient. I'm gonna revert these changes in a minute, but like, this is not gonna work. I'm still gonna get this AsyncAwait is not supported in client components errors. Why? Because the parent, which was that navigation bar, this down here renders that genre selector, this needs to be a client component. And that needed to be a client component because it uses that shopping cart again. So we can't just do this. Let's first, let's revert this change. So now the application should run again and let's go here for a moment. I've got a few components here and we're going to use those to see how things render and how we could influence them. And the first thing I'm gonna do is, let's close all of these for a moment. Find those components. Where did they go? Yeah, client or server. And I've got this page here, which renders this main component, which renders the render on client or on server or client. It in turn renders parent component, which says parent component. And it in turn renders a child component, which says child component. Now, where do they render now? Well, I've got the page.

Rendering Child Components on the Server

Short description:

The child components switched from server components to client components without any changes. It's just because it's the child component, it's being rendered by a child component, a client component, I should say. It has become a client component as well. If we want to make this a child server component again, we kind of have to render it in a different way. Client components should not be async and sometimes you get an error message that you're trying to do that. Having import server only here makes it very explicit. This needs to run on the server.

There is no use client there. I've got the parent components. There is no use client there. And I've got a child component, which doesn't have a use client either. Let's actually put a console dot log in here so we can see where these render. Rendering child components. We'll do the same here with parent. And we'll do the same in the page component, rendering. page. So, render is exactly the same. Open up the console window here, press F5, and there's the console window, and we see nothing. Go back to the server, and I should have a terminal open here. There, with the devtas, and somewhere right at the bottom, Here we can see rendering main page, rendering parent component, child components. And if I open the site by site for a moment, you can see, if I'm in the browser, I refresh, we see those messages appear in the console here. So these are server components. They're all renders on the server at the moment. Let's keep these site by site. So let's take the middle component, the parent component, and let's make this a child component. Not use child, use client. I saved this. On the server, we still see rendering parent, child, rendering main page, but now in the client here, we also see render parent and rendering child components. So the child components, without any change there, is switched from parent rendering to client rendering. And if I refresh this, you'll see the same thing, rendering parent, rendering child. We also see this on the server, but there we also see main page. The reason we see rendering parent component and rendering child component is because Next uses server-side rendering. If we use something else without server-side rendering, we would only see rendering main page here. So the child components switched from server components to client components without any changes. It's just because it's the child component, it's being rendered by a child component, a client component, I should say. It has become a client component as well. Now, suppose we want to do some server-side logic in here, this needs to be a server component. You might think, well, we can do use server in here. And in fact, use server exists, but it's not meant for this. If I save this, I'll get an error. It says to use server actions, please enable the feature flag, blah, blah, blah. You can use this but not here. It turns out, if we want to make this a child server component again, we kind of have to render it in a different way, and if we want to enforce this, there is an npm package which we can use. So I can do an import here of server only. Server only is a really, really small package. It basically checks whether it's being imported in a server or a client's package, and if it detects it's being imported in a client package, it will throw an error. So if I save, I'll get this error, saying you're importing a component that needs server only. It needs to run as a server component, but one of its parents is marked as useClient. Now let me comment this out for a moment and just briefly show you something which can go wrong. Let's make this async, and let's put a slight delay in there. Wait, because this has bitten me already several times. So we'll just make this wait 100 milliseconds. See what happens in the console here. Keeps on rerendering. This is not allowed in the Client Components and only after some time do you get this async await error. If you start at root, sometimes you don't get any error. I tried to navigate to that page and it just keeps rerendering, but the UI is never updated. Client components should not be async and sometimes you get an error message that you're trying to do that. And in other cases like this, you don't get an error message at all. So in a case like that, having import server only here makes it very explicit. This needs to run on the server. Let me stop that re-render cycle. So how do we change this to render on server? Well, we can't render it from here because this is a client component, but the page, that still is a server component. So, grabbing this and not rendering it from here but moving it over here and resolving this import should be perfectly fine. If I go back to server client, we can see it renders perfectly fine, no errors. Let me resize this a bit. We see the parent component, the child component, and now we only see rendering the parent component here, nothing about child components. And on the server, we see rendering main page, rendering child component. And for some reason, the parent component doesn't show up even though I would expect it to do so. Within F5, it does, if I refresh. For some reason, the first time it didn't. But now I'm rendering it on the server, but I've also changed the hierarchy. Previously that child component was a child of the parents component and was rendered in there, so I kinda want to do that again. Well, what we can do is relatively easy. We can say, well, it should render as a child of the parent component. Currently, parent component doesn't allow for that. But if I say when we've got some props here, props, with children.

Rendering Children and Splitting Components

Short description:

Render the children in the parent component without actually rendering the child component. The fact that the child component is a server component doesn't matter. Split the genre selector into two parts, keeping interactivity client-side and loading server-side.

So we know about the children and now we can say, render the children in here. And now we have the same nesting as before. Because what happens, the page or the server components renders parent component and it renders child components. Then the result of the rendering of child components is passed into parent component as a prop, children prop and parent component doesn't actually render the child component but just uses the results of the rendering. So the fact that child components is a server component, it doesn't matter, this parent component just gets some children and renders that. And of course I use children here, but it's just a prop. So any other name will go as well. Well, we can do that with that genre. So if I go back to genre selector, we can say, well, if we split this into two different parts and the interactivity here, et cetera, all of that stays client side, but the loading comes server side, we can actually make that work.

Creating Genre Loader Component

Short description:

In this section, we create a new component called genre loader and move the code into it. We import server only to ensure it is not loaded on the server by accident. The genre selector component is rendered within the genre loader component, and the genres are passed as a prop. The movie navigation still uses the genre selector, but it is now rendered within the site header, which is a server component. The genres are loaded on the server, and a sleep function is added to make the loading slower. The rendering of genres is placed in a suspense boundary, providing a fallback and resolving to the actual list of genres. This demonstrates how to control the rendering of slow server components within client components. We also briefly discuss the use of the server-only package and the useServer function for server actions.

So I'm going to create a new component, genre loader,.e6 I'm going to take that code, which I copied before from there. In order to load the Jonas, I'll move this into this component, and of course I need to make sure that that resolves. And I also want to do the same which I did a minute ago, make sure this is never loaded by accident on the server. So I want to import server only. From here, I want to render that genre selector component, passing in those genres. Not remove listener, return. Let's resolve this, and pass in the genres. And of course, that doesn't know about that prop yet, so let's add this. Get rid of this, get rid of all the loading here. So this is still a client component. Now we actually have to use that, because in the movie Select in, sorry, in the navigation we're still using the genre selector. Now I can't move this, change this into genre loader. Because this is the resolved. This is a client component. Genre loader is a server component. So that doesn't work because we just saw I can move this into whatever is the parent, which does render on the server. So see where main nav opens this render. So that's rendered here in the site header. The site header is actually a server component. So here I could say, well I want to render that. Genre loader. And I don't want that as a child, because that's kind of generic. So I just want to give this a more specific name, Something like that that needs to resolve. I still need to add this. This receives a prop now, which is of type ReactNode. So some kind of ReactNode. And now we can render that in the spot we want. And let's see if that works. Nope, because I made some error inside header. That should work better. So it loads. We can see we can load the movies, we can filter. Just like before. But now, if I look at the network and let me refresh this for a moment. We see there are no Fetch requests. All of those genres are loaded on the server. And while I'm at it, I might as well make this a bit slower. So in the genre Loader I'm going to add a sleep here. So now loading those genres is very slow. Let make this fast kind of slow. Okay. Move that scene over to the server. Look what we have. Make this full page again. By default, if I now press F5 you can see here that it's spinning, spinning. Nothing is loaded until those genres are actually completed. Which is not very nice. The first time you load that page, nothing happens. And that's more clearly visible if I go to new tab. So now we could say, well. We'll go to that main navigation. We've got genres here, let's put those in a suspense boundary. Fallback and not genre loader. But I'll do a little diff for the moment. So now just the rendering of those genres are in its own little suspense boundary. Now if I refresh you see we get three dots for the fallback and when it resolves we get the actual list of genres. So that's how you can take full control over slow server components, rendering inside of client components or anywhere else for that matter. This could, this is a client component now, but that could have been inside another server component as well. Which is really nice. So actually did a bit more than in this section just in the interest of time. So I did this shopping cart and the genre selector was still complete client component here. And I went over this part with what is a server component and what isn't. Remember that server-only package I used? The use server, we're not going to get to that, but that's for server actions. I'll briefly show it in the slides. And there we had and how to render that, and we actually did a bit more. We also did this part now, so am I there yet? Almost. Here we see the suspense with a slightly nicer fallback with a little spinner. So please go and do this. So calling ServerActions. And here we're gonna take a look at what UseServer, which I mentioned before, actually does.

React Server Actions and UseServer

Short description:

ServerActions are part of the React Server component specification. UseServer is used to execute functions on the server and make remote calls to client code. An example is adding an action to a form's onSubmit event.

So ServerActions are really cool. An initially I thought this was a Next.js thing but it turns out ServerActions are actually a React thing. They are part of the React Server component specification. So this will come to other frameworks that support Server components with React.

Now, UseServer is completely different from UseClient. UseClient means this component should render on the client. UseServer doesn't do the same thing. UseServer can be used on a file or a function base and it means that any functions in that file or that specific function annotated with UseServer should be executed on the server and any call from it to other code, client code typically, will automatically go over the wire become a remote call. So any code there has to be asynchronous.

Now the typical example you see is something like this. We've got a form here and normally in React, if you create a form, you'll have an onSubmit and an onSubmitHandler there and you'll put some code in there and that does whatever it needs to. Probably it's going to do an Ajax call back to the server. But now we add an action and that action points to a function and it's called the HandleSubmit function because it is called when it's submitted.

HandleSubmit Function and Server Execution

Short description:

HandleSubmit function executes on the server, not the client. It must be synchronous and can take any parameters. In this example, it uses form data.

Now, that HandleSubmit is defined up here and it has the new server declaration. Just like useClient, it has to be at the top of either the function or if it's a separate file, on top of that file, but that means that this function is going to execute on the server, not on the client. So, if I look, if I would have this code and I would execute it, this Console.log would be printed on the server. it also has to be in a synchronous function, even if you don't do any asynchronous work here, although in practice you probably will, but that is because it will be called over a fetch request from the client to the backend and it has to wait there for the response and send any response back to the client, which can await that. It can take any parameters you want, but with a quintessential example like this, where you use a form action, the parameter here will be of type form data and you can do a formdata.get and get any of those elements out there. But it's more flexible than that, it can be used in any case.

Executing Code on the Server with Server Actions

Short description:

To execute code on the server, the useServer function can be used. Server actions must be asynchronous and enabled in the next config. The server-only package ensures server-side execution and prevents inclusion in client code. The fetch server action function handles the communication between the client and server. It's important to note that server actions are experimental and should be used with caution. The rest of the code covers moving from pages to React Server components and the usage of app router and next/navigation.

And in my case, for instance, if I go back to movies, I can add some movies to the cart, go to checkouts and let me open the console window before I do. I can do a checkout here and I press OK. If I check the console over here, I can see that I ordered some movies. But in reality, I want to see that on the server. So let's go to the shopping cart. There is... There is this checkout dialog. If I go to the checkout dialog, We can see here that it calls into a checkout shopping cart function, passing the data. And that function is actually responsible here for printing. So I could go in here and say use server inside this function, but it's already in a separate file and I explicitly put this in a folder called server to indicate this really should be server side code. So, oops, I didn't want to jump to another file. I just want to go in here, so in here I could say, use server. So this will make this function execute on the server. Except right now, it still throws an error, because this is very much an experimental function. So it complains here, to use server actions, please enable the feature flag in your next config. So let's do that, open up the next config. There is an experimental section here. It has a server actions property in there, which we want to set to true and nothing else, just that. Now, I probably need to restart my server, my dev server, because that should survive this change, but in practice I find it typically dies. So if I refresh the client, I was expecting. Yeah, I was expecting this error now. So it says server actions must be async because they're going to go across the wire. So let's go back here. Where was it? There. Let's make this an async function. And then where we're calling it here, let's do an, oh, wait, so we're actually waiting for it to complete. And now if I open these side by side again, and now if I open the side by side again, now if I add a few movies to the shopping cart, I do another checkout. Magically, all my code is executed on the server and not on the client. So this is what userver is all about. What is it here? userver. This says okay, all of this code should be executed on the server. These functions should be asynchronous and they should be executed on the server and it will take care of all the marshalling between them instead. the server only package. The only thing it does, it will throw an error if that code is included in the client somehow. In this case, I do not want to add it because I actually just want to import this check out shopping cart function as if it was a regular function. If I look at the use case here, where was it used? In this checkout dialogue. I just import it as a normal function from some module. I can't tell whether it's client side, server side. So I can import it into the client just like normal. It's behind the scenes, all this magic happens and a whole lot of stuff is set up. And we can actually see that. So let's see. This bottom request here is the actual request which was made. And if we look at that, we can, if I look at the headers we can see it was a post, which was done. There's a bunch of stuff here. If I look at the initiator you can see this comes from server action producer. So there is this fetch server action function in there all of the boiler plate stuff to wire this up. I think this is pretty neat. It's kind of magic. You can just call a function as if it's locals yet it goes to the server executes on the server. I can put whatever I want in here. I've got console.logs in here but I could just have database code in here any server side code, because this executes on the server. Even though I imported this as just a function none of this ends up in the client code. And with this, all it does is generate an error if you import this into any client code, nothing more. In fact, if you look under the hood at what server only does, it's a package which only has one line of code, which is throw an error if I'm important to the client code. It's really, really simple. So here's the server action config we had to set. Remember it's experimental. I would not recommend using this in production code. I'm using it for demo code and trial things, but I'm not using this for anything which is in production. I do have some React Server components code in production, but also relatively low importance code like my own website I've done with Next. I'm using it there. But if that breaks, big deal. It's well enough tested, so I probably won't make it into production if there is a failure, but if there is, doesn't matter. The code I'm writing at the fintech startup, well, that's a lot more important. We don't want that crashing. I'm not gonna use React Server components or the server actions anytime soon there. So the rest of this code, we're not gonna do the exercise because we're out of time. I've also some stuff about moving from pages to React Server components. Mentioned both of this, you need to app router, you need to use the next slash navigation instead of next slash router.

Recommendations and Conclusion

Short description:

When developing components with React Server components, start with simple shared components that can run anywhere. Add server capabilities to components that need them, making them async and using the server-only package. Use useClient for client components that require browser APIs or interactivity. Be aware of caching differences between the app router and pages router in Next.js. React server components are a valuable addition, but their applicability depends on the interactivity of the application. Strict limits exist for the arguments and result types of server functions, requiring serialization as JSON. Challenges may arise when switching between server and client components, and thorough testing is necessary. Invalidation of components can be achieved through web hooks and invalidates path in Next.js. Thank you for attending the workshop and enjoy working with React server components!

You need to use the page.tsx, etcetera. No big deal, I'm gonna skip over this now because it's not the most important thing. It's also next specific. I do have some recommendations I wanna end up with. In general, when you develop components and you are using React Server components, start with simple components, what I call shared components here. They don't have any specific client or server code so they can run wherever they're needed. They might just have some diffs or so in there, but no states, no User Effects, no click handlers or mouse handlers, that kind of stuff. No database API code. So they can just run wherever they want. There is no server only there. There is no use client there. It just depends on whatever, wherever they're in the component stack.

Start adding server capabilities to component that need it. Make them async, make sure you import the server only package. So if you accidentally import them into a client part of your component stack, it will give a clear error. Usually you'll get a clear enough error, but not always as you've seen. In some cases, it might not throw an error. It might just start behaving weird. So being a bit more explicit helps a lot. And add use clients for all the client components where you need it, which means you're using browser APIs, you're using events, click handlers, you're using state side effects or hooks that do that. On my own website, for instance, I'm using some interactive behavior that needs to run on the client. I've got animations in there, so, with frame or motion. Well, that's something that needs to run on the client. If it's animations with CSS only, you can keep it on the server and that CSS will take care. But frame or motion needs to run on the client. Make sure if, at least if you're using Next.js, but that's the best option at the moment to learn about Next.js capabilities.

The caching can bite you. App router is different than the pages router. For the most part it's better, but it's also just in some cases different. For by accident, I mentioned server actions under next capabilities here, but that's not a next capability. That's actually part of the server component specification. So, all in all, I think React server components are a great addition. But keep in mind that it's not always applicable. For a very interactive application you probably want more on the client. For a relatively static application, you want more on the server. Say you've hosting blog pages from a some kind of like headless CMS, you're using headless WordPress for instance. Well, server components make perfect sense for that. For a trading application where you've got constantly changing stock prices. I think server components are not the best thing. Client components will work better. So, that's the end of the workshop. Thank you for joining. I hope it was useful. Got a nice link here. Share your thoughts if you want to share anything about it, it will take you to Twitter, at least assuming you're on Twitter and it will automatically tag me so I get to see it. And that's it. So, time for any final questions. And I see there are some questions in the chat window. Lots of thanks, thanks. So Richard- Everyone just saying thank you for a good talk, I think, or a good workshop. Which it was. So thank you for me as well. You're welcome, thank you. I noticed you had one question in here, which I didn't answer. I guess there's some strict limits on what arguments and result type server functions can be. Yes, that's completely true. Everything needs to be serializable, so you can't pass a React component with, or say the browser navigator object or something like that. It's all needs to be serializable as a JSON request. And under the hood, indeed, it's always a POST request, even if you manually call it like I did just now. Any other questions? The biggest challenge I encountered using RSC, I'm not sure if it's an RSC challenge, but I've had some interesting errors with when I used them. But I think that's more a next case. Like I might've mentioned this before, but I've got my own websites using RSC. It's not very interactive, but there is some stuff there. So I'm switching between server components and client components. I am testing everything with Playwrights. And for some reason, my Sentry error logs show up some errors which only appear when I'm doing my Playwright testing from the GitHub actions when I merge a pull request, or at least I check a pull request before I merge it. It doesn't happen when I run it locally, it apparently doesn't happen when I run it on the server, only there. I suspect that's just the next thing. I've also seen some runtimes errors, but again that's the next thing with older browsers, some older Android devices from China, which for some reason end up on my website, I'm not quite sure why, but they end up there and there are some global disk errors, which I've seen. For RSC, specifically the biggest issue is making sure that things are invalidated when you want to. Like if you're using a headless CMS for say a blog or something like that, well you make a change to a blog post, you wanna make sure that your page rerenders. So you need to set up a web hook and do an invalidates path in your next application. But again, that's more a next thing than RSC thing. End the meeting. Thank you all for being here. Hope to see you at some other workshop or maybe some training somewhere. Enjoy React, enjoy React server components and let me know if you create some interesting stuff with it.

Watch more workshops on topic

React Day Berlin 2022React Day Berlin 2022
53 min
Next.js 13: Data Fetching Strategies
WorkshopFree
- 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
React Advanced Conference 2021React Advanced Conference 2021
170 min
Build a Custom Storefront on Shopify with Hydrogen
Workshop
Hydrogen is an opinionated React framework and SDK for building fast, custom storefronts powered Shopify. Hydrogen embraces React Server Components and makes use of Vite and Tailwind CSS. In this workshop participants will get a first look at Hydrogen, learn how and when to use it, all while building a fully functional custom storefront with the Hydrogen team themselves.


React Advanced Conference 2022React Advanced Conference 2022
81 min
Build a Product Page with Shopify’s Hydrogen Framework
WorkshopFree
Get hands on with Hydrogen, a React-based framework for building headless storefronts. Hydrogen is built for Shopify commerce with all the features you need for a production-ready storefront. It provides a quick start, build-fast environment so you can focus on the fun stuff - building unique commerce experiences. In this workshop we’ll scaffold a new storefront and rapidly build a product page. We’ll cover how to get started, file-based routing, fetching data from the Storefront API, Hydrogen’s built-in components and how to apply styling with Tailwind.
You will know:
- Get started with the hello-world template on StackBlitz
- File-based routing to create a /products/example route
- Dynamic routing /products/:handle
- Hit the Storefront API with GraphQL
- Move the query into the Hydrogen app
- Update the query to fetch a product by handle
- Display title, price, image
&
description.
- Tailwind styling
- Variant picker and buy now button
- Bonus if there’s time: Collections page
Prerequisites: 
- A Chromium-based browser (StackBlitz)
- Ideally experience with React. A general web development background would be fine.

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

React Advanced Conference 2023React Advanced Conference 2023
27 min
Simplifying Server Components
Server Components are arguably the biggest change to React since its initial release but many of us in the community have struggled to get a handle on them. In this talk we'll try to break down the different moving parts so that you have a good understanding of what's going on under the hood, and explore the line between React and the frameworks that are built upon it.
React Summit 2023React Summit 2023
26 min
Server Components: The Epic Tale of Rendering UX
Server components, introduced in React v18 end these shortcomings, enabling rendering React components fully on the server, into an intermediate abstraction format without needing to add to the JavaScript bundle. 
This talk aims to cover the following points:
1. A fun story of how we needed CSR and how SSR started to take its place
2. What are server components and what benefits did they bring like 0 javascript bundle size
3. Demo of a simple app using client-side rendering, SSR, and server components and analyzing the performance gains and understanding when to use what
4. My take on how rendering UI will change with this approach
React Advanced Conference 2023React Advanced Conference 2023
28 min
A Practical Guide for Migrating to Server Components
Server Components are the hot new thing, but so far much of the discourse around them has been abstract. Let's change that. This talk will focus on the practical side of things, providing a roadmap to navigate the migration journey. Starting from an app using the older Next.js pages router and React Query, we’ll break this journey down into a set of actionable, incremental steps, stopping only when we have something shippable that’s clearly superior to what we began with. We’ll also discuss next steps and strategies for gradually embracing more aspects of this transformative paradigm.