React Server Components in Next.js 13
Abhishek Yadav
@h6165
FAQ
Isn't it already there in Next.js ? The SSR thing ?
SSR vs Server Components
SSR - we render the component on server side, usually with some data. The component is then *sent* to the browser where it becomes interactive (hydration)
Server Component - component rendered on server. Output (not component) sent to browser
What's the use ?
Server Component
- Reduced bundle size: can use heavy libraries that don't need to be sent to the client
- Can perform operations that can't be done on client - like database access
What's the catch
Server Component - can't be interactive - can't useState, can't use the context API
//
// Next.js: components in the 'app' directory
//
import { heavyFunction } from 'heavy-library';
export function MyComponent() {
const result = heavyFunction()
return (
<div>
{ result }
</div>
);
}
Example: server component in Next.js
No code from 'heavy-library' reaches the browser
'use client'; // Next.js: declare it's a client component
import { useState } from 'react';
export function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
Example: client components in Next.js
- Client components - should declare themselves as so: 'use client'
- Other than that there's nothing special
// Next.js
// client component called within server component
//
import { heavyFunction } from 'heavy-library';
import { Counter as CounterOnClient } from './counter'
export function MyServerComponent() {
const result = heavyFunction()
return (
<div>
{ result }
<CounterOnClient />
</div>
);
}
Example
Call Client component from the server component
- Server components can call client components*
- Client components can also call server components*
*conditions apply
Mingling Server and client components
Server Components
- Dan Abramov announced in Dec 2020
- Shared a long video, and some sample code
- The idea being: build it for frameworks - like Next.js
- Next.js 13 incorporated it, and released in Oct 2022
- Feature is still in beta
- Refs:
- The announcement video
- Announcement post
- Sample code
- The RFC
- Next.js 13 announcement
The project status
Server components
- Props: server component -> client
- Import: server component in client
- Preventing poisoning
- Using third party components
- Fetch de-duplication
The Devil in the details
-
Props should be serializable
- Okay: Number, String, Object, Array
- Not okay: Functions
- Network boundary: Props going from server to client component are crossing the network boundary
Devil in details: Server -> Client props
// Next.js
// client component called within server component
// with props
import { Counter as CounterOnClient } from './counter'
export function MyServerComponent() {
const x = "hello"
const fn = ()=>{}
return (
<>
<CounterOnClient prop1={x} /> // Ok
<CounterOnClient prop1={fn} /> // NOT OK
</>
);
}
- Import fails
- Server components can be used but not imported within client component
- Component code can't go. Rendered component goes
Devil in details: Importing Server Component in Client
'use client';
import MyServerComponent from './ServerComponent'; // Fails here
export function CounterOnClient() {
return (
<>
<MyServerComponent />
// other stuff
</>
);
}
- Server Component can be used via the render prop pattern
- In a parent Server component, both can be imported
- And then our MyServerComponent can be included as a child of the CounterLayout
Devil in details: Importing Server Component in Client
'use client';
// Server Component called as children
function CounterLayout({ children }) {
return (
<>
{ children }
// other stuff
</>
);
}
// Next.js
// Using server components
// inside of client component
//
import MyServerComponent from './ServerComponent';
import { CounterLayout } from './counterLayout'
export function MainServerComponent() {
return (
<CounterLayout>
<MyServerComponent />
</CounterLayout>
);
}
- Modules like these can be imported as usual in the client component. This can happen by accident.
- This is poisoning
- Only ServerComponents are prevented. Importing the rest is legal.
Devil in details: Preventing poisoning
'use client';
// This is legal
import { myServerOnlyFn } from './utils'
function CounterLayout() {
const value = myServerOnlyFn()
return (
<>
{ value }
// other stuff
</>
);
}
//
// A function that should be called
// on server side only
//
export function myServerOnlyFn() {
// My
// Super
// secret
// algorithm
return Math.random();
}
- Use the server-only package to mark a module as server-only
- Build fails if client-component tries importing such a module
- (Next.js only)
Devil in details: Preventing poisoning
'use client';
// This fails now
import { myServerOnlyFn } from './utils'
function CounterLayout() {
const value = myServerOnlyFn()
return (
<>
{ value }
// other stuff
</>
);
}
import "server-only"; // NPM package
//
// A function that should be called
// on server side only
//
export function myServerOnlyFn() {
// My
// Super
// secret
// algorithm
return Math.random();
}
-
Third party component libraries may fail in server components, because they may be interactive (useState)
-
If they have the 'use-client' declaration, then its okay
-
We can write wrapper components for such situation
Devil in details: Using third party components
// Next.js
import { SliderComponent } from 'slider-lib'
export function ServerComponent() {
return (
// Fails
<SliderComponent />
);
}
Devil in details: Using third party components
// Next.js
import { MySliderComponent } from './sliderWrapper'
export function ServerComponent() {
return (
// Works
<MySliderComponent />
);
}
//
// Wrapper component
//
'use-client'
import { SliderComponent } from 'slider-lib'
export function MySliderComponent() {
return (
<SliderComponent />
);
}
The wrapper
Devil in details: Fetch de-duplication
-
Next.js recommendations:
-
fetch data in server components, not client
-
fetch in each (server) component that needs it.
-
-
Don't: fetch it all at once in a parent, and passing down as props. (Context is not available anyway)
-
Next.js performs a de-duplication on these requests
-
Benefit: reduced coupling
Server components
That's all
React Server Components in Next.js 13
By Abhishek Yadav
React Server Components in Next.js 13
- 537