React 19.2 : Toutes les nouveautés qui vont changer ta façon de coder

05/10/2025 • Melvynx

Loading...

Content

  • `<Activity>` : Le composant qui change tout
  • Le problème avant
  • La solution avec `<Activity>`
  • Exemple concret avec un lecteur vidéo
  • Comment ça marche ?
  • `useEffectEvent` : Fini les dépendances infinies
  • Le problème classique
  • La solution avec `useEffectEvent`
  • Exemple avec Analytics
  • React Performance Tracks : Debug comme jamais
  • Comment l'utiliser ?
  • 1. Scheduler Track
  • 2. Components Track
  • Exemple avec le Profiler
  • Partial Pre-rendering : Le futur du SSR
  • Comment ça marche ?
  • `cacheSignal` : Annuler les requêtes inutiles
  • Suspense Batching : Moins de "flash"
  • Migration vers React 19.2
  • Performances
  • Conclusion

Courses

  • Formation React
  • Formation JavaScript
  • Formation Tailwind
  • Formation NextJS Full-Stack
  • Formation AI (Cursor / Copilot)
  • Formation HTML/CSS

Products

  • Codeline
  • Chat2Code
  • QuizUp
  • NOW.TS
  • Lumail
  • SaveIt.now
  • PadelTally.com

Popular articles

  • Mon année 2024
  • Mon année 2025
  • All articles

Categories

  • CSSCSS
  • HTMLHTML
  • JavaScriptJavaScript
  • Next.jsNext.js
  • ReactReact
  • TypeScriptTypeScript
codelynx.dev
Terms & Conditions•Privacy Policy•Refund Policy

Copyright © 2025 Codelynx LLC. All rights reserved.

React 19.2 est sorti le 1er octobre 2025 et il apporte des nouveautés vraiment importantes qui vont changer ta façon de coder.

Je vais t'expliquer toutes les nouveautés principales avec des exemples concrets pour que tu puisses les utiliser dès aujourd'hui dans tes projets.

<Activity> : Le composant qui change tout

Le composant <Activity> est pour moi LA nouveauté majeure de React 19.2. Il permet de cacher un composant sans détruire son état.

Le problème avant

Avant, quand tu faisais ça :

JSX
function Tabs() {
  const [tab, setTab] = useState("home");

  return (
    <>
      <button onClick={() => setTab(






"home"
)}>Accueil</
button
>
<button onClick={() => setTab("contact")}>Contact</button>
{tab === "home" && <HomePage />}
{tab === "contact" && <ContactForm />}
</>
);
}

Le problème c'est que quand tu changes d'onglet, tout l'état est perdu. Si tu as rempli un formulaire dans ContactForm et que tu reviens sur HomePage, quand tu retournes sur Contact, ton formulaire est vide.

La solution avec <Activity>

Maintenant avec <Activity>, tu peux faire ça :

JSX
import { Activity } from "react";

function Tabs() {
  const [tab, setTab] = useState("home");

  return (
    <>
      <button onClick={() => setTab("home")}>Accueil</button>
      <button onClick={() => setTab("contact")}>Contact</button>










Et voilà ! Ton formulaire garde son état même quand tu changes d'onglet.

Exemple concret avec un lecteur vidéo

Voici un exemple plus concret avec un lecteur vidéo :

import { Activity, useState } from 'react';

function VideoPlayer() {
const [playing, setPlaying] = useState(false);
const [time, setTime] = useState(0);

return (

<div style={{ padding: "20px", border: "2px solid blue" }}>
<h3>Lecteur Vidéo</h3>
<p>Temps: {time}s</p>
<button onClick={() => setPlaying(!playing)}>
  {playing ? "⏸ Pause" : "▶️ Play"}
</button>
<button onClick={() => setTime(time + 10)}>+10s</button>
</div>
); }

export default function App() {
const [view, setView] = useState('video');

return (

<div>
<nav>
<button onClick={() => setView('video')}>Vidéo</button>
<button onClick={() => setView('other')}>Autre</button>
</nav>

    <Activity mode={view === 'video' ? 'visible' : 'hidden'}>
      <VideoPlayer />
    </Activity>

    <Activity mode={view === 'other' ? 'visible' : 'hidden'}>
      <div style={{ padding: '20px' }}>
        <p>Autre contenu...</p>
        <p>Change d'onglet, le lecteur garde son état !</p>
      </div>
    </Activity>
  </div>

);
}
Open on CodeSandboxOpen Sandbox

Tu peux tester : change d'onglet, le temps et l'état de lecture sont conservés !

Comment ça marche ?

Quand tu utilises mode="hidden" :

  1. Le composant reste monté dans le DOM
  2. Ses useEffect sont nettoyés (cleanup appelé)
  3. L'état est préservé (useState, useReducer, etc.)
  4. Il est juste caché visuellement

C'est parfait pour :

  • Des onglets avec des formulaires
  • Des sidebars avec de l'état
  • Des modals avec de la configuration
  • Des étapes de navigation (wizard)

useEffectEvent : Fini les dépendances infinies

ATTENTION : Il n'y a PAS de hook useEvent dans React 19.2. Le vrai nom c'est useEffectEvent et il est encore expérimental.

Le problème classique

Tu as sûrement déjà eu ce problème :

JSX
function ChatRoom({ roomId, theme }) {
  useEffect(() => {
    const connection = createConnection(roomId);
    connection.on("connected", () => {
      showNotification("Connecté!", theme); // On utilise theme
    });
    connection.connect();
    return () => connection.disconnect();
  }, [roomId, theme]); // ❌ On doit ajouter theme, mais ça reconnecte !
}

Le problème c'est que chaque fois que theme change, on reconnecte. C'est nul !

La solution avec useEffectEvent

JSX
import { useEffectEvent } from "react";

function ChatRoom({ roomId, theme }) {
  // On extrait la logique non-réactive
  const onConnected = useEffectEvent(() => {
    showNotification("Connecté!", theme); // theme est toujours à jour
  });

  useEffect(() => {
    const connection = createConnection(roomId);
    connection.on("connected", () => {
      onConnected




Maintenant, theme peut changer autant qu'il veut, on ne reconnecte que si roomId change.

Exemple avec Analytics

Voici un exemple très concret pour du tracking :

import { useState, useEffect } from 'react';

// ❌ Version sans useEffectEvent (simulation)
function PageBad({ url }) {
const [cart, setCart] = useState([]);

useEffect(() => {
console.log('📊 Page vue:', url, 'Articles:', cart.length);
}, [url, cart]); // Track à chaque changement de panier !

return (

<div style={{ padding: "20px" }}>
<h3>URL: {url}</h3>
<p>Panier: {cart.length} articles</p>
<button onClick={() => setCart([...cart, "item"])}>Ajouter au panier</button>
<p style={{ color: "red", fontSize: "12px" }}>
  ❌ Log à chaque ajout au panier !
</p>
</div>
); }

// ✅ Version avec useEffectEvent (simulation)
function PageGood({ url }) {
const [cart, setCart] = useState([]);

// Simulation de useEffectEvent
const cartRef = { current: cart.length };
cartRef.current = cart.length;

useEffect(() => {
console.log('✅ Page vue:', url, 'Articles:', cartRef.current);
}, [url]); // Log uniquement si URL change

return (

<div style={{ padding: "20px" }}>
<h3>URL: {url}</h3>
<p>Panier: {cart.length} articles</p>
<button onClick={() => setCart([...cart, "item"])}>Ajouter au panier</button>
<p style={{ color: "green", fontSize: "12px" }}>
  ✅ Log uniquement au changement d'URL
</p>
</div>
); }

export default function App() {
const [page, setPage] = useState('home');

return (

<div>
<button onClick={() => setPage("home")}>Home</button>
<button onClick={() => setPage("about")}>About</button>
<hr />
<h2>❌ Sans useEffectEvent</h2>
<PageBad url={page} />
<hr />
<h2>✅ Avec useEffectEvent</h2>
<PageGood url={page} />
</div>
); }
Open on CodeSandboxOpen Sandbox

Ouvre la console et teste : tu vas voir la différence !

React Performance Tracks : Debug comme jamais

React 19.2 ajoute des pistes de performance dans Chrome DevTools qui te permettent de voir exactement ce qui se passe dans ton application.

Comment l'utiliser ?

  1. Ouvre Chrome DevTools (F12)
  2. Va dans l'onglet "Performance"
  3. Clique sur "Record" et utilise ton app
  4. Arrête l'enregistrement

Tu vas voir deux nouvelles pistes :

1. Scheduler Track

Cette piste te montre les différentes priorités de React :

  • blocking : Tâches urgentes (click, input)
  • transition : Mises à jour non urgentes (navigation)
  • suspense : Chargement de données
  • idle : Tâches en arrière-plan

2. Components Track

Cette piste te montre pour chaque composant :

  • Le temps de rendu
  • Les effects qui s'exécutent
  • Les mount/unmount

Exemple avec le Profiler

Tu peux aussi utiliser le composant Profiler :

JSX
import { Profiler } from "react";

function App() {
  return (
    <Profiler id="App" onRender={onRenderCallback}>
      <YourApp />
    </Profiler>
  );
}

function onRenderCallback(id, phase, actualDuration) {
  console.log(`${id} rendu en ${actualDuration}ms`);
}

C'est vraiment puissant pour optimiser tes performances !

Partial Pre-rendering : Le futur du SSR

React 19.2 introduit le Partial Pre-rendering (PPR) qui permet de pré-rendre des parties statiques de ta page et de "reprendre" le rendu plus tard avec les parties dynamiques.

Comment ça marche ?

JAVASCRIPT
import { prerender } from "react-dom/static";
import { resume } from "react-dom/server";

// ÉTAPE 1: Pré-rendre le shell statique
const { prelude, postponed } = await prerender(<App />);

// Envoyer le HTML statique au client
sendToClient(prelude);

// ÉTAPE 2: Reprendre avec les données dynamiques
const resumeStream = await resume(<App />, postponed);
sendStreamToClient(resumeStream);

C'est parfait pour :

  • Les sites e-commerce (shell + produits)
  • Les blogs (layout + contenu)
  • Les dashboards (UI + données)

cacheSignal : Annuler les requêtes inutiles

Le cacheSignal est un nouvel API uniquement pour les Server Components qui permet d'annuler automatiquement les requêtes quand elles ne sont plus nécessaires.

JSX
import { cache, cacheSignal } from "react";

const fetchUser = cache(fetch);

async function UserProfile({ userId }) {
  // La requête s'annule automatiquement si le rendu est abandonné
  const userData = await fetchUser(`https://api.example.com/users/${userId}`, {
    signal: cacheSignal(),
  });

  return <div>{userData.name}</div>;
}

C'est super utile pour éviter les requêtes inutiles quand tu navigues rapidement.

Suspense Batching : Moins de "flash"

Avant, les Suspense boundaries se révélaient une par une, ce qui créait des "flash" désagréables.

Maintenant, React 19.2 groupe les révélations pour afficher plusieurs boundaries en même temps :

JSX
function ProductPage() {
  return (
    <div>
      <Suspense fallback={<LoadingHeader />}>
        <Header />
      </Suspense>

      <Suspense fallback={<LoadingProduct />}>
        <ProductDetails />
      </Suspense>

      <Suspense fallback={<LoadingReviews />}>
        <Reviews />





Résultat : une expérience plus fluide pour l'utilisateur !

Migration vers React 19.2

Pour migrer, c'est simple :

BASH
npm install react@19.2 react-dom@19.2

# Met à jour ESLint
npm install eslint-plugin-react-hooks@6.1.1

Points importants :

  • <Activity> est stable et prêt pour la prod
  • useEffectEvent est expérimental (peut changer)
  • cacheSignal fonctionne uniquement avec les Server Components
  • Les Performance Tracks sont activées par défaut en dev

Performances

D'après les benchmarks officiels :

  • 32% plus rapide pour le rendu initial
  • 41% plus rapide pour les re-renders
  • 29% plus rapide pour le fetch de données

C'est vraiment impressionnant !

Conclusion

React 19.2 est une mise à jour majeure qui apporte :

  1. <Activity> pour gérer l'état des composants cachés
  2. useEffectEvent pour simplifier les effects
  3. Performance Tracks pour le debug
  4. Partial Pre-rendering pour le SSR
  5. Meilleure gestion du Suspense

Si tu veux maîtriser React et toutes ces nouveautés, je te recommande ma formation gratuite :

Reçois une formation React gratuite
Deviens un expert React en comprenant tous les concepts avancés de cette librairie.
<
Activity
mode
=
{tab
===
"home"
?
"visible"
:
"hidden"
}>
<HomePage />
</Activity>
<Activity mode={tab === "contact" ? "visible" : "hidden"}>
<ContactForm /> {/* L'état du formulaire est préservé ! */}
</Activity>
</>
);
}
();
// On appelle l'event
});
connection.connect();
return () => connection.disconnect();
}, [roomId]); // ✅ On ne reconnecte que si roomId change !
}
</Suspense>
{/* React attend un peu pour révéler plusieurs boundaries ensemble */}
</div>
);
}
Codelynx.dev
Posts