Context: Evolution of Rendering Approaches
Client-Side Rendering (CSR)
- How it works: Everything is rendered in the browser.
- Pros: Fast interactivity.
- Cons: Heavy initial load and poor SEO.
Server-Side Rendering (SSR)
- How it works: Content is rendered on the server and sent to the client, where hydration enables interactivity.
- Pros: Improved SEO.
- Cons: Still requires JavaScript in the browser.
Static Site Generation (SSG)
- How it works: Content is pre-rendered at build time.
- Pros: Fast initial load.
- Cons: Limited content flexibility.
Incremental Static Regeneration (ISR)
- How it works: Content is rendered statically and revalidated at predefined intervals.
- Pros: Combines static performance with periodic updates.
- Cons: Updates aren’t real-time.
React Server Components (RSC)
- How it works: Content is rendered on the server with no need for JavaScript on the client (except for client components).
-
Pros:
- Smaller bundle size
- Faster initial load
- Interactivity supported via client components
Comparing SSR and RSC
SSR Example:
In this example, we have an application that displays the title and description of posts.
- Clone the repository:
git clone https://github.com/hoshdev/poc-nextjs-rsc
- Install dependencies:
npm install
- Switch to the 1-rcc branch:
git checkout 1-rcc
- Open
App.tsx
.
You’ll notice it's a client component (using the use client
directive at the top).
In this example, we retrieve post content inside a useEffect
:
useEffect(() => {
console.log("browserUseEffect", typeof window !== "undefined");
getPosts()
.then((posts) => setPosts(posts))
.catch((err) => console.log("err", err));
}, []);
- Observe: All JavaScript is sent to the client.
It’s a simple example with a small amount of data, but imagine this in a real application. Here's the flow:
- The content is created on the server (the first
console.log
isfalse
). - Then, it's sent to the browser (the next
console.log
istrue
). - Finally, once hydrated, the component becomes interactive, and the
console.log
inside theuseEffect
is displayed in the browser.
RSC Example:
- Switch to the 2-rsc branch:
git checkout 2-rsc
- In
App.tsx
, you’ll see a server component.
It doesn't have the use client
directive at the top. Since it's a server component, it runs on the server.
You can use async/await
to retrieve data:
const PostsPage = async () => {
const posts = await getPosts();
};
Note: You can access any Node.js feature in server components, like interacting with a database, the file system, or using
process.env
.Observe: No JavaScript for server components is sent to the client. Compare this with the SSR example screenshot.
Adding Interactivity in RSC:
If you need interactivity, you can include client components. These are sent to the browser, allowing for dynamic behavior.
- Switch to the 3-rsc-rcc branch:
git checkout 3-rsc-rcc
- Here, we added a client component that handles interactivity. So, the JavaScript for this component is sent to the browser,l but just client component.
Some Final Tips
Server Environment:
-
Leverage Node.js features: You can use Node.js-specific functionality like
async/await
,process.env
, and more. -
No hooks in server components: You cannot use React hooks (such as
useState
oruseEffect
) in server components since they are meant to be client-side only.
Event Handling:
- Use client components for interactivity: Server components are responsible for rendering, but for event handling (like clicks or form submissions), you must use client components to manage the interactivity.
By understanding the evolution of rendering approaches—from CSR to SSR, SSG, ISR, and RSC—you can make more informed decisions about the architecture of your application, improving both performance and SEO.
Need further details? Contact me
Let’s learn by doing, collaborating and facing real project challenges together learning from each other! Learn More
Top comments (0)