Les nouveautés de React 19.2

React a sorti sa troisième mise à jour de l'année avec la version 19.2 qui est l'occasion de l'introduction d'un nouveau composant Activity et d'un nouveau hook useEffectEvent. Dans cet article je vous propose d'explorer plus en profondeur ses nouveautés et de voir quelques cas d'utilisation.

Sommaire

  • 00:00 Introduction
  • 00:20 Le composant Activity
  • 05:59 useEffectEvent()
  • 08:26 Changement de prefix useId()
  • 09:36 Inspecteur de performance
  • 12:54 Autres changements
  • 15:45 Conclusion

Le composant <Activity>

Le composant <Activity> est un nouveau composant qui offre une nouvelle approche pour gérer l'affichage et les masquage d'éléments.

// Avant
{showCounter && <Counter />}

// Après
<Activity mode={showCounter ? "visible" : "hidden"}>
  <Counter />
</Activity>;

Même si le résultat de ces 2 approches est similaire (élément masqué quand le showCounter est false) le fonctionnement interne est complètement différent dans le cas d'Activity.

  • Les composants enfant d'un <Activity> sont toujours rendu (même si ils sont masqué). Apparaissent dans le DOM avec un display: none!important
  • Les effets (useEffect) des composants enfant d'un Activity ne sont pas exécutés si le mode de l'Activity est hidden. Ils seront exécutés dès lors que l'élément devient visible.
  • Les composants enfants gardent leur état entre chaque affichage.

Au premier abord, ce nouveau composant ne semble pas vraiment intéréssant mais il permet en réalité de répondre à certains besoins.

Element du DOM persistant

Un premier cas d'utilisation peut être un élément du DOM pour lequel on souhaiterait garder son état. Par exemple dans le cas d'une vidéo :

  • On veut garder la position de lecture lorsque l'élément redevient visible.
  • La vidéo doit se mettre en pause lorsque l'élément se masque.

Vu que le composant Activity déclenche les effets lors de l'affichage ou du masquage notre composant vidéo ressemblera à ça :

export function Video () {
  const video = useRef<HTMLVideoElement>(null)

  useEffect(() => {
    const videoEl = video.current
    videoEl?.play()
    return () => {
      videoEl?.pause()
    }
  }, []);

  return <video src="/ascenseur.mp4" controls playsInline ref={video} muted></video>
}

Ensuite, notre composant peut être utilisé dans un Activity

<Activity mode={showCounter ? 'visible' : 'hidden'}>
  <Video/>
</Activity>

Precharger des données

Un autre cas d'utilisation est le préchargement des données. Vu que le composant, même masqué, est rendu une logique de récupération asynchrone peut être déclenchée.

export function Posts() {
  const posts = use(fetchData("/posts")); // Fonction asynchrone, nécessite un Suspense
  return (
    <div>
      <h2>Articles</h2>
      <ul>
        {posts.map((post) => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  );
}

En combinant Activity et Suspense on peut masquer le composant tout en chargeant ses données :

<Suspense fallback={"loading..."}>
  <Activity mode={showCounter ? "visible" : "hidden"}>
    <Posts />
  </Activity>
</Suspense>

Avec cette approche, les données sont chargées en avance et l'utilisateur n'aura pas à attendre lorsqu'il souhaitera afficher les articles.

Le Hook useEffectEvent()

Le nouveau Hook useEffectEvent() permet de résoudre les cas où useEffect utilise des variables interne au composant.

const [count, setCount] = useState(0);

const logCount = () => {
  console.log("count", count);
};

useEffect(() => {
  setTimeout(() => {
    logCount();
  }, 2000);
}, []);

Le problème ici, est que la fonction logCount() utilisé dans le useEffect est celle du premier rendu. Aussi, si même si la valeur de count a changé la console continuera d'afficher count 0. On pourrait inclure la fonction comme dépendance du useEffect() mais cela déclencherait des appels non nécessaire.

useEffectEvent va permettre de créer une version invariable de la fonction qui utilisera la dernière version de l'état du composant.

const [count, setCount] = useState(0);

const logCount = useEffectEvent(() => {
  console.log("count", count);
});

useEffect(() => {
  setTimeout(() => {
    logCount();
  }, 2000);
}, []);

L'Inspecteur de performance

Avec la version 19.2, de nouvelles options apparaissent dans les React Developer Tools sous la forme de 2 nouvelles pistes dans l'onglet "Performance". Ces 2 pistes permettent une exploration plus en profondeur sur le fonctionnement du Scheduler de React et sur le temps de rendu des différents composants. On notera surtout la présence d'une section Cascading Update qui permettra d'identifier plus facilement les changements d'état en cascade dans un composant.

useEffect(() => {
  setPosts(/*...*/); // Déclenche un update en cascade
});

Changements de prefix pour useId()

C'est un changement mineur mais qui peut être intéréssant. Le hook useId() change de prefix et renvoie maintenant une chaine qui est un sélecteur CSS valide.

useId();
// React 19.1 => ":r:0"
// React 19.2 => "_r_0"

Autres changements

Le reste des changements concerne plutôt le rendu côté serveur (RSC) :

  • Un système de prerendering permettant au serveur de rendre une partie du code en amont
  • Un regroupement des rendu pour les Suspense pour améliorer l'expérience utilisateur
  • Le support des WebStream pour NodeJS
  • Un changement dans le comportement du plugin eslint-plugin-react-hooks
Publié
Technologies utilisées
Auteur :
Grafikart
Partager