Skip to content
Learni
Voir tous les tutoriels
React

Comment maîtriser les React Server Components en 2026

Read in English

Introduction

Les React Server Components (RSC) révolutionnent le développement React en 2026, en rendant par défaut le rendu côté serveur. Introduits avec React 18 et maturisés dans Next.js 13+ (App Router), ils permettent d'accéder directement au filesystem, à la base de données et aux APIs sans exposer de code client, réduisant drastiquement la taille du bundle JS (jusqu'à 90% de réduction). Contrairement aux SPA traditionnelles, les RSC fusionnent SSR et CSR de manière hybride : les composants server s'exécutent uniquement sur le serveur, génèrent du HTML statique ou dynamique, et supportent le streaming pour une interactivité immédiate.

Pourquoi c'est crucial en 2026 ? Avec l'essor de l'IA et des apps data-heavy, les RSC optimisent le TTFB (Time To First Byte), le SEO et la sécurité (pas de secrets client-side). Ce tutoriel expert vous guide pas à pas : du setup à des patterns avancés comme le caching avec React.cache, le streaming Suspense et les Server Actions pour les mutations. À la fin, vous créerez des apps scalables prêtes pour la prod. (128 mots)

Prérequis

  • Node.js 20+ et npm/yarn/pnpm
  • Connaissances avancées en React 18+, TypeScript et Next.js 14+
  • Familiarité avec l'App Router (pas de Pages Router)
  • Un éditeur comme VS Code avec extension TypeScript
  • Accès à une API ou DB pour les exemples data (ex: JSONPlaceholder)

Initialiser le projet Next.js App Router

terminal
npx create-next-app@latest rsc-expert --typescript --tailwind --eslint --app --src-dir --import-alias "@/*"
cd rsc-expert
npm run dev

Cette commande crée un projet Next.js 15+ avec TypeScript, Tailwind CSS, ESLint et App Router activé. Le flag --app assure l'utilisation du nouveau router compatible RSC. Lancez npm run dev pour démarrer le serveur de dev sur http://localhost:3000. Évitez les anciennes templates Pages Router, incompatibles avec les patterns RSC avancés.

Comprendre la structure App Router

L'App Router organise les fichiers en app/ : layout.tsx (persistent), page.tsx (route principale), loading.tsx (fallback streaming). Tous les fichiers .tsx sont par défaut des Server Components (pas de 'use client'). Les props sont sérialisables (primitives, React elements). Analogy : imaginez les RSC comme des fonctions PHP old-school, mais avec React : zéro JS client inutile pour le rendu initial.

Premier Server Component basique

app/page.tsx
export default function HomePage() {
  return (
    <main className="flex min-h-screen flex-col items-center justify-center p-24">
      <h1 className="text-4xl font-bold">Premier RSC</h1>
      <p>Ceci s'exécute UNIQUEMENT sur le serveur.</p>
      <p>Pas de bundle JS pour ce composant !</p>
    </main>
  );
}

Ce page.tsx est un RSC pur : rendu serveur, HTML statique envoyé au client. Aucune directive 'use client', donc zéro JS hydraté ici. Testez en inspectant le réseau : payload HTML pur, bundle client minimal. Piège : n'utilisez pas useState ou useEffect ici (erreur de compilation).

Data Fetching dans les RSC

Les RSC excellent en data fetching serveur-side avec fetch() natif (caching automatique via Next.js). Utilisez React.cache pour persister les résultats entre requêtes. En 2026, unstable_cache est stabilisé pour un contrôle fin du TTL et des clés de cache.

RSC avec fetch et React.cache

app/users/page.tsx
import { unstable_cache } from 'react';

const getUsers = unstable_cache(
  async () => {
    const res = await fetch('https://jsonplaceholder.typicode.com/users', {
      next: { revalidate: 3600 }
    });
    return res.json();
  },
  ['users'],
  { revalidate: 3600 }
);

export default async function UsersPage() {
  const users = await getUsers();
  return (
    <div>
      <h1>Utilisateurs (RSC)</h1>
      <ul>
        {users.map((user: any) => (
          <li key={user.id}>{user.name}</li>
        ))}
      </ul>
    </div>
  );
}

unstable_cache (stable en 2026) wrappe fetch pour un cache persistant par clé ['users'] et TTL de 1h. Le next: { revalidate: 3600 } active ISR. Accédez via /users. Avantage : data fraîche sans re-fetch client. Piège : clés de cache dynamiques (userId) nécessitent template literals.

Composant Client imbriqué dans RSC

app/counter/client-counter.tsx
'use client';

import { useState } from 'react';

export function ClientCounter({ initialCount }: { initialCount: number }) {
  const [count, setCount] = useState(initialCount);
  return (
    <div>
      <p>Compteur client: {count}</p>
      <button onClick={() => setCount(count + 1)}>+1</button>
    </div>
  );
}

Directive 'use client' rend ce composant hydratable client-side. Props initialCount sérialisables depuis RSC parent. Imbriquez dans un RSC pour hybride parfait. Piège : évitez de passer fonctions ou objets non-sérialisables comme props.

Hybride RSC + Client avec props

app/page.tsx
import { ClientCounter } from './counter/client-counter';

import { unstable_cache } from 'react';

const getInitialData = unstable_cache(async () => ({ count: 42 }), ['initial-data']);

export default async function HomePage() {
  const data = await getInitialData();
  return (
    <main className="p-8">
      <h1>RSC Hybride</h1>
      <ClientCounter initialCount={data.count} />
    </main>
  );
}

RSC parent fetch data, passe props statiques au Client Component enfant. Résultat : rendu serveur initial + interactivité client. Inspectez : HTML statique + petit JS pour counter. Évite le waterfall fetching.

Streaming avec Suspense

Pour les apps data-heavy, Suspense stream les RSC : fallback immédiat, puis chunks HTML asynchrones. Parfait pour timelines ou dashboards.

Streaming RSC avec Suspense

app/dashboard/page.tsx
import { Suspense } from 'react';

async function SlowUsers() {
  await new Promise(resolve => setTimeout(resolve, 2000));
  const users = await fetch('https://jsonplaceholder.typicode.com/users').then(r => r.json());
  return <ul>{users.slice(0,5).map((u: any) => <li key={u.id}>{u.name}</li>)}</ul>;
}

export default function Dashboard() {
  return (
    <div>
      <h1>Dashboard Streaming</h1>
      <Suspense fallback={<p>Chargement utilisateurs...</p>}>
        <SlowUsers />
      </Suspense>
    </div>
  );
}

Suspense stream le RSC SlowUsers après 2s simulant un slow fetch. Fallback affiché instantanément. Avantage : UI progressive. Piège : pas de Suspense imbriqué sans canary features.

Server Actions pour mutations

app/actions/page.tsx
'use server';

import { revalidatePath } from 'next/cache';

export async function increment(prev: number) {
  'use server';
  revalidatePath('/actions');
  return prev + 1;
}

export default function ActionsPage({ initial }: { initial: number }) {
  return (
    <form action={increment.bind(null, initial)}>
      <p>Valeur: {initial}</p>
      <button formAction={increment}>Incrémenter (Server Action)</button>
    </form>
  );
}

Server Actions ('use server') gèrent mutations sans API routes. revalidatePath rafraîchit le cache. Bind pour passer initial. Sécurisé : exécution serveur. Piège : actions asynchrones doivent être awaited.

Bonnes pratiques

  • Toujours prioriser RSC : minimisez 'use client' pour bundles légers.
  • Cache agressif : utilisez unstable_cache + fetch({next: {tags: ['posts']}}) pour invalidation granulaire.
  • Props minimales : passez seulement primitives/éléments statiques vers clients.
  • Suspense partout : wrappez fetches pour streaming optimal.
  • Tests : mock fetch dans RSC avec MSW pour CI/CD.

Erreurs courantes à éviter

  • 'use client' abusif : rend tout client-side, perdant les gains RSC.
  • Fonctions non-sérialisables en props : crash hydration (utilisez Server Actions).
  • Pas de cache : re-fetch à chaque load, dégradant perf (ajoutez unstable_cache).
  • Oubli Suspense : blocage UI sur slow fetches (toujours wrapper).

Pour aller plus loin

Approfondissez avec la doc officielle React RSC et Next.js App Router. Découvrez nos formations Learni sur React & Next.js pour du mentoring expert. Explorez Turbopack pour builds 10x plus rapides.