React 19.2 est la troisième release majeure de l'année 2025, et la plus substantielle. Couplée à Next.js 16 et ses Cache Components, elle redéfinit ce qu'une application web peut faire en termes de performance et d'expérience utilisateur.

React 19.2, publiée le 1er octobre 2025, introduit trois nouveautés majeures : le composant ViewTransition, le hook useEffectEvent, et l'Activity API. Next.js 16, sorti en juillet 2026, apporte les Cache Components — un nouveau modèle de programmation qui combine Partial Pre-Rendering (PPR) et directive use cache pour une navigation instantanée.

Ensemble, ces deux releases transforment la façon dont on construit des applications web : animations natives sans librairie tierce, effects stables sans re-rendus inutiles, et pré-rendering partiel pour des pages à la fois statiques et dynamiques. Ce guide explore chaque feature avec des exemples concrets et des cas d'usage réels.


Vue d'ensemble : l'écosystème React 19.2 + Next.js 16

Écosystème React 19.2 + Next.js 16Cartographie des fonctionnalités de React 19.2 et Next.js 16

Si vous êtes sur Next.js 16, vous utilisez déjà React 19.2 car l'App Router embarque React Canary. Aucune installation séparée n'est nécessaire. Pour les projets React standalone :

npm install react@19.2 react-dom@19.2
npm install eslint-plugin-react-hooks@latest  # v6.1.1+ pour useEffectEvent linting

ViewTransition : les transitions déclaratives natives

Le problème

Historiquement, animer des transitions de route ou de changement d'état en React nécessitait une librairie tierce (Framer Motion, react-transition-group) et un nombre significatif de plumbing. L'API native document.startViewTransition() du navigateur existe mais sa coordination manuelle avec le cycle de rendu React est complexe.

La solution React 19.2

Le composant <ViewTransition> gère automatiquement cette coordination. Il s'active quand :

  • Le contenu change via Suspense boundaries (fallback → contenu)
  • Un changement d'état dans un startTransition
  • Une valeur différée via useDeferredValue
import { ViewTransition } from 'react';

function ProductGallery({ products, selectedId }) {
  return (
    <ViewTransition>
      <ProductList products={products} />
      <ProductDetail id={selectedId} />
    </ViewTransition>
  );
}

Shared-element transitions

La fonctionnalité phare : les shared-element transitions, où un élément semble se déplacer fluidement d'un layout à un autre. Par exemple, une image de produit qui se transforme en image pleine taille quand on clique.

<ViewTransition>
  {view === 'grid' && <ProductCard product={product} />}
  {view === 'detail' && <ProductFullView product={product} />}
</ViewTransition>

// Dans ProductCard :
<img 
  style={{ viewTransitionName: `product-${product.id}` }}
  src={product.image} 
/>
// Dans ProductFullView :
<img 
  style={{ viewTransitionName: `product-${product.id}` }}
  src={product.image} 
/>

Le navigateur anime automatiquement la transition entre les deux éléments partageant le même view-transition-name.

Événements et Web Animations API

ViewTransition supporte des callbacks optionnels pour contrôler l'animation via JavaScript :

<ViewTransition
  onEnter={(event) => {
    // Personnaliser l'animation d'entrée
    const animation = event.snapshot.animate([
      { opacity: 0, transform: 'scale(0.8)' },
      { opacity: 1, transform: 'scale(1)' },
    ], { duration: 300 });
    return () => animation.cancel();
  }}
  onExit={(event) => { /* ... */ }}
  onShare={(event) => { /* ... */ }}
  onUpdate={(event) => { /* ... */ }}
>
  <Content />
</ViewTransition>

Règles importantes :

  • Un seul événement se déclenche par <ViewTransition> par Transition
  • onShare prend précédence sur onEnter et onExit
  • Chaque événement doit retourner une fonction de cleanup

Support navigateur

En mai 2026, le support global des same-document View Transitions est d'environ 78% :

  • Chrome 111+, Edge 111+
  • Safari 18+ (incluant iOS 18)
  • Firefox : support partiel

Le composant React gère automatiquement la dégradation sur les navigateurs non supportés.


useEffectEvent : des effects stables sans re-rendus

Le problème résolu

Le cas classique : une connexion chat qui se reconnecte inutilement chaque fois que le thème change, juste parce que le callback onConnect lit la valeur de theme.

// AVANT : reconnexion inutile à chaque changement de thème
function ChatRoom({ roomId, theme }) {
  useEffect(() => {
    const connection = createConnection(roomId);
    connection.on('connected', () => {
      showNotification('Connecté !', theme); // theme dans les deps
    });
    connection.connect();
    return () => connection.disconnect();
  }, [roomId, theme]); // ← theme cause re-exécution
}

La solution

useEffectEvent extrait la logique non-réactive hors du tableau de dépendances :

// APRÈS : connexion stable, theme toujours à jour
import { useEffectEvent } from 'react';

function ChatRoom({ roomId, theme }) {
  const onConnected = useEffectEvent(() => {
    showNotification('Connecté !', theme);
  });

  useEffect(() => {
    const connection = createConnection(roomId);
    connection.on('connected', onConnected);
    connection.connect();
    return () => connection.disconnect();
  }, [roomId]); // ← theme n'est plus dans les deps
}

Règles d'usage

Quand utiliser useEffectEvent vs useEffectArbre de décision pour savoir quand utiliser useEffectEvent

  1. Déclarer dans le même composant que l'Effect qui l'utilise
  2. Ne pas passer à des children — les Effect Events sont limités au composant propriétaire
  3. Utiliser eslint-plugin-react-hooks@latest (v6.1.1+) pour le linting
  4. Ne pas wrapper tout dedans — useEffectEvent est pour la logique événementielle, pas pour silencer le lint

Activity API : préserver l'état sans rendre

L'Activity API permet de garder des parties de l'UI montées mais cachées, en préservant leur état tout en démontant les effects et en différant les mises à jour.

import { Activity } from 'react';

function TabContainer({ activeTab }) {
  return (
    <>
      <Activity mode={activeTab === 'profile' ? 'visible' : 'hidden'}>
        <ProfileTab />
      </Activity>
      <Activity mode={activeTab === 'settings' ? 'visible' : 'hidden'}>
        <SettingsTab />
      </Activity>
    </>
  );
}

Cas d'usage typiques :

  • Onglets où l'utilisateur bascule fréquemment
  • Modals avec formulaire dont on ne veut pas perdre l'état
  • Listes virtualisées avec position de scroll à préserver

Next.js 16 Cache Components : PPR + use cache

Le modèle de programmation

Les Cache Components de Next.js 16 représentent un changement fondamental : au lieu de choisir entre statique et dynamique au niveau de la page, vous pouvez maintenant pré-rendre statiquement des portions de pages tout en gardant d'autres parties dynamiques.

Architecture Cache Components Next.js 16Architecture du Partial Pre-Rendering et des Cache Components dans Next.js 16

Partial Pre-Rendering (PPR)

Le PPR permet à Next.js de servir un shell statique immédiatement, puis de streamer les parties dynamiques :

// app/products/[id]/page.tsx
import { Suspense } from 'react';

export const experimental_ppr = true;

export default function ProductPage({ params }) {
  return (
    <div>
      {/* Statique : pré-rendu au build, servi immédiatement */}
      <ProductHeader id={params.id} />
      
      {/* Dynamique : streamé après */}
      <Suspense fallback={<ReviewsSkeleton />}>
        <Reviews productId={params.id} />
      </Suspense>
    </div>
  );
}

Directive use cache

La directive use cache permet de marquer explicitement des segments comme cachables :

// Cache statique au build
async function ProductHeader({ id }) {
  'use cache';
  
  const product = await fetch(`/api/products/${id}`).then(r => r.json());
  return <h1>{product.name}</h1>;
}

// Cache avec revalidation
async function getRecommendedProducts(userId) {
  'use cache';
  
  const products = await fetch(`/api/recommendations/${userId}`).then(r => r.json());
  return products;
}

// Cache avec tag pour invalidation
async function getUserProfile(userId) {
  'use cache';
  
  const user = await db.user.findUnique({ where: { id: userId } });
  return user;
}
// Invalidation : revalidateTag('user-profile');

Nouvelles APIs de cache

Next.js 16 introduit des APIs de cache raffinées :

APIUsage
updateTag()Invalide et recalcule un tag de cache spécifique
refresh()Force le rafraîchissement du cache
revalidateTag()Invalide le cache pour un tag (raffiné)
// Action qui invalide le cache après mutation
'use server';
import { revalidateTag } from 'next/cache';

export async function updateProfile(userId, data) {
  await db.user.update({ where: { id: userId }, data });
  revalidateTag('user-profile');
}

Turbopack stable : le bundler par défaut

Next.js 16 fait de Turbopack le bundler par défaut pour toutes les applications. Les bénéfices :

  • Démarrage et compilation plus rapides (Rust-based)
  • Turbopack File System Caching (beta) : startup encore plus rapide
  • React Compiler (stable) : intégration built-in pour la memoization automatique
// next.config.ts
export default {
  // Turbopack est maintenant le défaut, pas besoin de flag
  // Pour le désactiver (non recommandé) :
  // turbopack: false,
};

Les bases de React 19 que la 19.2 prolonge

Si votre projet vient de React 18, la 19.2 s'appuie sur des API arrivées avec React 19. Elles simplifient le code de tous les jours :

  • use() lit une promesse directement dans un composant, avec Suspense pour l'état de chargement. Il lit aussi un contexte, et contrairement aux autres hooks, il peut être appelé dans une condition.
  • useActionState (anciennement useFormState) gère l'état d'un formulaire relié à une Server Action : il renvoie l'état courant, l'action à passer au formulaire et un booléen isPending pour le chargement.
  • useOptimistic affiche tout de suite le résultat attendu d'une action pendant que la requête part, puis revient en arrière si elle échoue. Plus besoin d'une bibliothèque tierce pour ce cas.
  • ref est une prop comme les autres. Les composants fonction la reçoivent directement : forwardRef n'est plus nécessaire.
'use client';
import { useActionState } from 'react';
import { submitContactForm } from './actions';

export function ContactForm() {
  const [state, action, isPending] = useActionState(submitContactForm, null);
  return (
    <form action={action}>
      <input name="email" type="email" required />
      <button disabled={isPending}>{isPending ? 'Envoi...' : 'Envoyer'}</button>
      {state?.error && <p>{state.error}</p>}
    </form>
  );
}

Le React Compiler complète ces API : il analyse vos composants à la compilation et ajoute la mémoïsation là où elle sert. Les useMemo et useCallback écrits à la main deviennent inutiles dans la plupart des cas. Il ne corrige pas un composant qui enfreint les règles de React (effet de bord pendant le rendu, objet modifié en place) : ce composant ne sera simplement pas optimisé.


Comparatif : React 19.1 vs 19.2 + Next.js 15 vs 16

Comparatif React 19.1 vs 19.2 et Next.js 15 vs 16Radar comparatif des capacités entre React 19.1/19.2 et Next.js 15/16

Le radar ci-dessus compare cinq dimensions : Performance (Turbopack, PPR), DX (React Compiler, useEffectEvent), Animations (ViewTransition), Caching (Cache Components), et Stabilité (maturité des APIs).


Plan de migration : de Next.js 15 + React 19.1 vers 16 + 19.2

Avant tout : vous êtes encore sur le Pages Router ?

Les Cache Components, use cache et le PPR ne fonctionnent qu'avec l'App Router. Si votre projet utilise encore pages/, migrez d'abord, sans tout réécrire d'un coup :

  1. Recensez les routes qui utilisent getServerSideProps, getStaticProps et getStaticPaths : elles deviendront des composants async qui chargent leurs données eux-mêmes.
  2. Faites cohabiter app/ et pages/. Next.js accepte les deux dossiers en même temps : les nouvelles pages vont dans app/, les anciennes restent en place.
  3. Migrez page par page, des plus simples aux plus complexes. Ajoutez 'use client' uniquement aux composants qui utilisent des hooks ou des événements, et remplacez les routes API par des Server Actions quand la logique s'y prête.
  4. Mesurez avant et après avec Lighthouse ou PageSpeed Insights sur les pages migrées.

Le Pages Router reste maintenu : gardez-le si une bibliothèque essentielle n'est pas compatible avec les Server Components, ou si l'équipe n'a pas le temps de migrer.

Étape 1 : Mise à jour des dépendances

npm install next@latest react@19.2 react-dom@19.2
npm install eslint-plugin-react-hooks@latest

Étape 2 : Breaking changes à gérer

// Async params (breaking change Next.js 16)
// AVANT (Next.js 15) :
export default function Page({ params }) {
  return <Product id={params.id} />;
}

// APRÈS (Next.js 16) :
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
  const { id } = await params;
  return <Product id={id} />;
}

Étape 3 : Adoption progressive des Cache Components

// 1. Activer PPR sur une page
export const experimental_ppr = true;

// 2. Identifier les segments statiques
async function StaticHeader() {
  'use cache';
  const data = await fetch('https://api.example.com/config').then(r => r.json());
  return <Header config={data} />;
}

// 3. Garder les segments dynamiques dans Suspense
<Suspense fallback={<Skeleton />}>
  <DynamicContent />
</Suspense>

Étape 4 : Migration des effects vers useEffectEvent

Identifiez les effects qui se ré-exécutent trop souvent à cause de dépendances non-réactives. Extrayez la logique événementielle avec useEffectEvent.


Performance réelle : ce que les Cache Components changent

D'après les benchmarks Next.js et les retours terrain, les Cache Components apportent :

MétriqueSans PPRAvec PPRGain
FCP (First Contentful Paint)1.1s0.3s-73%
LCP (Largest Contentful Paint)2.4s0.8s-67%
TTFB180ms45ms-75%
TBT (Total Blocking Time)290ms50ms-83%

Ces chiffres sont des estimations basées sur les documentation Next.js et les tests de l'équipe Vercel. Les gains réels dépendent de la proportion de contenu statique vs dynamique dans vos pages.


Conclusion

React 19.2 et Next.js 16 représentent le duo le plus significatif pour le développement web front-end en 2026. Les View Transitions éliminent le besoin de librairies d'animation tierces. Les Cache Components avec PPR rendent obsolète le compromis historique entre statique et dynamique. useEffectEvent résout un papercut vieux de 10 ans dans la gestion des effects.

Pour les équipes qui hésitent à migrer, le parcours est progressif : on peut adopter ces features une par une, page par page. Si votre entreprise veut accélérer cette migration, notre expertise développement web couvre les migrations Next.js 16 avec optimisation performance, et notre service de développement SaaS intégre les Cache Components dès le design initial.

La combinaison React 19.2 + Next.js 16 n'est pas une mise à jour incrémentale — c'est un changement de paradigme vers des applications web qui rivalisent avec le natif en termes de fluidité et de performance.