NextJS 13 was released last week and its biggest feature is a new app directory with a new file-based routing system. The new folder also supports React Server Components.
This marks a new evolution for React server-side rendering. Previously, server-side rendering with React followed a process such as this:
Server loads all data needed for the page (either at build time or when the request is made).
Server renders all react components to HTML.
Client loads all HTML.
Client then loads JavaScript code.
The client "hydrates" the HTML, rerendering all react components and comparing it with the received HTML.
Finally, the page is interactive.
With React Server Components, the process is transformed to:
Server renders initial HTML skeleton, to the first Suspense boundary, and starts fetching data.
The skeleton HTML is sent to the client.
As the server finishes data loading, components are rendered on the server and streamed to the client as HTML.
The client loads React and only React Client Components.
The client hydrates only the React Client Components.
Finally, the page is interactive.
Thus, the client needs to load much less JavaScript, only for interactive components.
For a demonstration, I created a simple gallery viewer for HelloPaint. You can find the deployed version here and the GitHub repository here.
During this project, I learned:
Rendering mui components (material-ui) as server components was an issue (Emotion is possibly unsupported as of now?).
Tailwind and DaisyUI functioned well.
Data is loaded using the
use()
React hook, which takes a promise and waits until the promise is resolved.
In the context of data loading with graphql, urql, and graphql-codegen, it looks something like this:
1import {graphql} from "../../lib/gql";
2import {Client} from "@urql/core";
3import { use } from "react";
4import Image from "next/image";
5import {Like} from "./like";
6
7const client = new Client({
8 url: "https://hellopaint.io/api/gateway/graphql",
9});
10
11
12const galleryQuery = graphql(/* GraphQL */`
13 query GalleryPosts {
14 galleryPosts(query: {limit: 30}) {
15 id
16 title
17 imageUrl
18 description
19 }
20 }
21`)
22
23const load = async () => {
24 return client.query(galleryQuery, {}).toPromise();
25}
26
27
28export default function Home() {
29
30 const data = use(load());
31
32 [...]
33
However, if you attempt to use useState
from within a server component, you'll find an error stating that this is only functional within a Client Component.
To bypass this, adding use client;
at the top of the file will ensure that it functions as a normal React component. You can continue to explore these new features and updates directly from the NextJS 13 blog post.