Kodokon kodokon.com

React moderne : Server Components, use, useTransition, useOptimistic

Explorez les composants serveur, la lecture de promesses avec use et les mises à jour optimistes de React 19.

11 min · 3 questions

Ouvrir cette leçon dans Kodokon

Les React Server Components (RSC) redéfinissent la frontière client-serveur. Un composant serveur s'exécute uniquement côté serveur : son code ne rejoint jamais le bundle client, il peut être async, lire la base de données ou le système de fichiers directement, et son résultat est envoyé au navigateur sous forme d'un flux sérialisé (le payload RSC) que React fusionne avec l'arbre client. En contrepartie, il n'a ni état, ni effets, ni accès au navigateur : pas de useState, pas de useEffect, pas de gestionnaires d'événements. Il ne se re-rend jamais côté client.

JSX
// Composant serveur : jamais envoye au client.
export default async function NotesPage() {
  const notes = await db.notes.findAll();
  return (
    <ul>
      {notes.map((note) => (
        <li key={note.id}>{note.title}</li>
      ))}
    </ul>
  );
}
Un composant serveur async interroge la base directement.

L'interactivité vit dans les composants client, marqués par la directive 'use client' en tête de fichier. Cette directive ne marque pas « un composant client » mais une frontière : tout ce que ce module importe bascule aussi côté client. Les props qui traversent la frontière doivent être sérialisables : objets simples, tableaux, promesses... mais jamais de fonctions ordinaires ni d'instances de classe.

JSX
'use client';

import { useState } from 'react';

export function LikeButton({ initialCount }) {
  const [count, setCount] = useState(initialCount);
  return (
    <button onClick={() => setCount(count + 1)}>
      {count} likes
    </button>
  );
}
La directive 'use client' délimite la zone interactive.

React 19 introduit use, une API qui lit la valeur d'une promesse ou d'un contexte. Contrairement aux hooks, use peut être appelé dans une condition ou une boucle. Passé une promesse, il suspend le composant jusqu'à la résolution, en s'appuyant sur la frontière Suspense la plus proche. Le pattern idiomatique : un composant serveur crée la promesse sans l'attendre, la passe en prop, et un composant client la consomme avec use : le serveur commence à streamer la page sans attendre la donnée.

JSX
import { use, Suspense } from 'react';

function Comments({ commentsPromise }) {
  const comments = use(commentsPromise);
  return comments.map((c) => (
    <p key={c.id}>{c.text}</p>
  ));
}

function Page({ commentsPromise }) {
  return (
    <Suspense fallback={<Spinner />}>
      <Comments commentsPromise={commentsPromise} />
    </Suspense>
  );
}
use suspend le composant jusqu'à la résolution de la promesse.

Côté interactions, useTransition marque une mise à jour comme non urgente et expose isPending pour afficher un indicateur discret sans bloquer la saisie. useOptimistic complète le duo pour les mutations réseau : vous affichez immédiatement l'état espéré pendant qu'une action asynchrone s'exécute ; à la fin de l'action (succès ou échec), React abandonne la valeur optimiste et réaffiche l'état réel, celui de la source de vérité.

JSX
const [optimisticLikes, addOptimisticLike] =
  useOptimistic(likes, (count, delta) => count + delta);

function handleLike() {
  startTransition(async () => {
    addOptimisticLike(1);
    await saveLike();
    // A la fin, React reaffiche l'etat reel.
  });
}
L'interface réagit immédiatement, le serveur confirme ensuite.

Quiz de validation

Vérifiez que vous avez bien retenu les points clés de cette leçon.

  1. Qu'est-ce qu'un composant serveur ne peut pas faire ?
    • Être déclaré async et attendre une requête
    • Lire directement la base de données
    • Utiliser useState et les gestionnaires d'événements
    • Rendre des composants client comme enfants
  2. Quelle règle des hooks l'API use est-elle autorisée à enfreindre ?
    • Être appelée en dehors d'un composant
    • Être appelée dans une condition ou une boucle
    • Être appelée après un return anticipé du module
    • Être appelée dans une classe
  3. Que devient la valeur de useOptimistic quand l'action asynchrone se termine ?
    • Elle devient l'état permanent du composant
    • Elle est abandonnée et l'état réel reprend la main
    • Elle est fusionnée avec l'état réel
    • Elle est conservée jusqu'au prochain rendu manuel