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.
Comments