React Server Components

Understand React Server Components (RSC), when to use them, and how they integrate with frameworks like Next.js for better performance.

React Server Components (RSC) run on the server and send rendered HTML to the client. They reduce client-side JavaScript and improve initial page load.

Server vs Client Components

Server Components render on the server, have no client-side JavaScript, and can directly access backend resources. Client Components are traditional React components that run in the browser.

Benefits

Zero bundle size for server components, direct database/API access, improved initial load time, and automatic code splitting.

When to Use Each

Use Server Components for static content, data fetching, and accessing backend resources. Use Client Components for interactivity, hooks, browser APIs, and event handlers.

The "use client" Directive

Mark a component as a Client Component by adding "use client" at the top of the file. Everything it imports becomes part of the client bundle.

Data Fetching

Server Components can be async and fetch data directly. No need for useEffect or client-side data fetching libraries.

Code Examples

Server Component with Data

UserList.jsx
// This is a Server Component by default in Next.js App Router
// No "use client" directive needed

async function UserList() {
  // Direct database access - runs on server only
  const users = await db.users.findMany({
    orderBy: { createdAt: 'desc' },
    take: 10,
  });

  return (
    <ul className="user-list">
      {users.map(user => (
        <li key={user.id}>
          <span>{user.name}</span>
          <span>{user.email}</span>
        </li>
      ))}
    </ul>
  );
}

// In a page component
export default async function UsersPage() {
  return (
    <main>
      <h1>Users</h1>
      {/* This data fetching happens on the server */}
      <UserList />
    </main>
  );
}

Client Component

Counter.jsx
"use client"; // This directive makes it a Client Component

import { useState } from 'react';

export function Counter({ initialCount = 0 }) {
  const [count, setCount] = useState(initialCount);

  return (
    <div className="counter">
      <p>Count: {count}</p>
      <button onClick={() => setCount(c => c + 1)}>
        Increment
      </button>
      <button onClick={() => setCount(c => c - 1)}>
        Decrement
      </button>
    </div>
  );
}

// Usage in a Server Component
// page.jsx (Server Component)
import { Counter } from './Counter';

export default async function Page() {
  const initialValue = await fetchInitialCount();

  return (
    <div>
      <h1>Interactive Counter</h1>
      {/* Client Component nested in Server Component */}
      <Counter initialCount={initialValue} />
    </div>
  );
}

Mixing Server and Client

ProductPage.jsx
// page.jsx - Server Component
import { Suspense } from 'react';
import { ProductDetails } from './ProductDetails';
import { AddToCart } from './AddToCart';
import { Reviews } from './Reviews';

export default async function ProductPage({ params }) {
  // Fetch on server
  const product = await getProduct(params.id);

  return (
    <main>
      {/* Server Component - no JS sent to client */}
      <ProductDetails product={product} />

      {/* Client Component for interactivity */}
      <AddToCart productId={product.id} price={product.price} />

      {/* Streaming with Suspense */}
      <Suspense fallback={<ReviewsSkeleton />}>
        <Reviews productId={product.id} />
      </Suspense>
    </main>
  );
}

// AddToCart.jsx
"use client";

import { useState } from 'react';
import { useCart } from '@/hooks/useCart';

export function AddToCart({ productId, price }) {
  const [quantity, setQuantity] = useState(1);
  const { addItem } = useCart();

  const handleAdd = () => {
    addItem({ productId, quantity, price });
  };

  return (
    <div>
      <input
        type="number"
        value={quantity}
        onChange={e => setQuantity(Number(e.target.value))}
      />
      <button onClick={handleAdd}>Add to Cart</button>
    </div>
  );
}

Frequently Asked Questions

When should I use 'use client'?

Add 'use client' when you need: useState/useEffect hooks, event handlers (onClick, onChange), browser APIs (localStorage, window), or third-party libraries that use client-side features.

Can I pass functions from Server to Client Components?

No, you cannot pass functions as props from Server to Client Components. Functions aren't serializable. Instead, pass data and define the functions in the Client Component, or use Server Actions.

Do Server Components replace API routes?

For data fetching, often yes - Server Components can directly access databases. But API routes are still needed for: client-side mutations, webhooks, non-React clients, and third-party integrations.

Need React Help?

Slashdev.io builds production-ready React applications for businesses of all sizes.

Get in Touch