Explaining React Server Components

8 messages
Can you explain how React Server Components differ from Client Components?
7:53 PM
A
Great question! Here's the key distinction: Server Components run exclusively on the server. They: - Never ship JavaScript to the browser - Can directly access databases, file systems, and secrets - Cannot use useState, useEffect, or browser APIs - Are the default in Next.js 13+ App Router Client Components run in the browser. They: - Are marked with 'use client' at the top - Can use React hooks and browser APIs - Support interactivity (onClick, onChange, etc.) - Are hydrated on the client side The mental model: think of Server Components as the "shell" that renders once on the server, and Client Components as the interactive "islands" embedded within that shell.
7:53 PM
When should I use one over the other?
7:53 PM
A
A good rule of thumb: Use Server Components when: - Fetching data from a database or API - Rendering static or non-interactive content - Accessing environment variables or secrets - Building layouts, pages, and static sections Use Client Components when: - You need useState or useEffect - Handling user events (clicks, input changes) - Using browser-only APIs (localStorage, window) - Integrating with third-party libraries that need the DOM A practical pattern: keep as much of your component tree as Server Components, and only push down to Client Components at the leaf level where interactivity is actually needed.
7:53 PM
Show me a code example of the split pattern
7:53 PM
A
Here's a clean example of the Server/Client split pattern:
tsx
// ProductPage.tsx — Server Component (no 'use client')
import AddToCartButton from './AddToCartButton';

async function ProductPage({ id }: { id: string }) {
  // Direct DB call — only possible in Server Component
  const product = await db.products.findById(id);

  return (
    <div>
      <h1>{product.name}</h1>
      <p>{product.description}</p>
      <p>${product.price}</p>
      {/* Only this leaf needs to be a Client Component */}
      <AddToCartButton productId={id} />
    </div>
  );
}
tsx
// AddToCartButton.tsx — Client Component
'use client';
import { useState } from 'react';

export function AddToCartButton({ productId }: { productId: string }) {
  const [added, setAdded] = useState(false);

  return (
    <button onClick={() => setAdded(true)}>
      {added ? 'Added to Cart ✓' : 'Add to Cart'}
    </button>
  );
}
The product data fetching stays on the server, and only the interactive button becomes a Client Component.
7:53 PM
This is really clear, thanks! One more thing — can Server Components pass props to Client Components?
7:53 PM
A
Yes — with one important constraint: props must be serializable. Server Components can pass: - Strings, numbers, booleans - Plain objects and arrays - Dates (serialized as ISO strings) They cannot pass: - Functions (callbacks) - Class instances - Symbols - Anything that can't be JSON-serialized This is because props cross the server-client boundary as serialized data. If you need to pass a callback, the pattern is to keep the event handler inside the Client Component itself, not pass it down from the server.
7:53 PM

ChatAI can make mistakes. Consider checking important information.