Jul 17 2023
In October 2022, React Server Components were introduced and the Next.js Team worked hard on incorporating it into Next.js over the next several months.
With “app router” going stable now, RSC is officially supported in Next.js here’s what you need to know!
What is a Server Component?
Previously, Next.js rendered React on the server as html and hydrated the sent html with event listeners & interactivity in the browser.
Data fetching on individual pages was done through various framework-specific functions like
getStaticProps, etc. and via API endpoints present in the
pages/api directory. With the new “app router” as they like to call it, these special functions are obsolete in the favour of RSC.
Here’s an example of a Next.js page present at the “/” path
Notice that this is an async function where we’re awaiting prisma db call for fetching posts.
“But, wait… won’t this run on a browser too?”
This is different from the way it used to run on server AND browser, the special thing about a Server Component is that they run ONLY on the server and never on the browser.
When client requests for the page, the server waits for the awaited promise
findMany() to finish, renders the page and sends the resulting HTML to the client.
Next.js will consider all the components as a Server Component by default, so if we try adding any interactive features like a state variable or a
useEffect or try calling the
window object, It errors out.
Let’s follow the above error, it requires us to add a line
"use client"; in the component
Hmm… the linter warns us for using the an async function in a client component, so this means, Next.js is now taking this as a client component, let’s look at the result in the browser…
Quick Note: Prisma can’t run in a browser environment, it needs Node.js runtime for normal functioning.
Now, it is talking about the
db.ts where we are initializing a Prisma Client and the fact that this error is occuring in the browser, it must mean that the component is now being run in the browser too during the hydration phase.
This means that our component is now behaving like to used to do in previous Next.js versions.
Why need Server Components?
Previously when we wanted to fetch db data on the server, we’d use
getStaticProps to fetch data and pass it as props to the top-level component of that route.
This approach had a draw-back, for the nested components to consume the fetched route data, it had to be either passed through prop-drilling or via a global state management solution.
With Server Components, individual components can now fetch the data they consume directly on the server.
And as we see, in lot of places our app doesn’t need to be highly interactive, it just needs to fetch and to statically display the data, in those places, React Server Components work like a charm, by replacing all the overhead of useEffects & state variables by just simple HTML.
Quick Note: Client Components are primarily rendered on the client, but with Next.js, they can also be pre-rendered on the server and hydrated on the client.
Making a Mental Model
To make a working mental model of a system where server components are involved, there are some rules to it:
- Components marked with
“use client”will have their children automatically marked as client components too. The component marked explicitly as
“use client”can be thought of as a boundary where its parent elements are Server components and its children are client components.
- Server components can import client components and have them as children.
- Client components can’t import server components, however, they can have client components as children or as props passed into them.
This way, we can add “islands” of interactivity and make our mental model around composing different types of components in our app.
Next.js Server Actions
Server components provide really efficient & convenient way to fetch data in static components, but… what about the dynamic client components?
It seems like they still need to make fetch calls to a traditional API endpoint to get data in cases where prop-drilling is not possible.
Have a demo of Next’s new experimental feature “Server Actions”
As visible from the above pictures,
“use server” directive can be used to declare a function or a file as a “server action” which is a fancy way of saying that this function runs only on server.
The really cool thing about server actions is that you can even call them from within client components.
This will change the whole data-fetching scenario for Next.js apps and to TypeScript, they’re just normal functions, we get fully-typed responses from server actions as if the boundary between client and server doesn’t even exist!
All in all, the latest updates to the Next.js directly mean huge productivity gains for developers and performance gains for users.
Here’s all the project code referred in the article - github.com/oaktreeapps/rsc-nextjs-demo
Always refer docs for all your questions, you’ll probably find the answers there ;)