Visionner la vidéo

Le Hook le plus sous-estimé de React : useSyncExternalStore

  React

Introduction

Bienvenue sur ce post où nous allons explorer un hook React méconnu mais extrêmement utile : useSyncExternalStore. Ce hook peut grandement faciliter la synchronisation de vos données provenant de sources externes, comme le localStorage ou les API du navigateur.

Nous commencerons par la méthode classique avec useEffect, puis nous verrons comment optimiser notre code avec useSyncExternalStore. Enfin, nous terminerons par un exemple pratique avec l’API navigator.onLine pour suivre l’état de connexion de l’utilisateur.

Synchronisation avec useEffect

Imaginons que nous voulons synchroniser une valeur provenant du localStorage. La première idée qui vient à l’esprit est d’utiliser useEffect pour surveiller les changements.

Voici comment pourrait ressembler notre composant :

"use client";

import { faker } from "@faker-js/faker";
import { useEffect, useState } from "react";
import { Button } from "./ui/button";

const EMAIL_KEY = "email";

export default function LocalStorageDemo() {
  const [value, setValue] = useState(
    () => localStorage.getItem(EMAIL_KEY) ?? ""
  );

  useEffect(() => {
    const handleStorageChange = () => {
      setValue(localStorage.getItem(EMAIL_KEY) as string);
    };

    window.addEventListener("storage", handleStorageChange);

    return () => {
      window.removeEventListener("storage", handleStorageChange);
    };
  }, []);

  function updateEmailHandler() {
    const newEmail = faker.internet.email();
    localStorage.setItem(EMAIL_KEY, newEmail);
    window.dispatchEvent(new Event("storage"));
  }

  return (
    <div className="space-y-6 mt-8">
      <p>Adresse email : {value}</p>
      <Button onClick={updateEmailHandler}>Changer l&apos;email</Button>
    </div>
  );
}

Voici l’explication du code ci-dessus :

Bien que cette approche fonctionne, elle peut devenir complexe à gérer, surtout si vous avez plusieurs sources de données externes à synchroniser.

Optimisation avec useSyncExternalStore

Le hook useSyncExternalStore est conçu pour synchroniser de manière efficace des états externes dans vos composants React.

Voici comment refactorer le composant précédent en utilisant useSyncExternalStore :

"use client";

import { faker } from "@faker-js/faker";
import { useSyncExternalStore } from "react";
import { Button } from "./ui/button";

const EMAIL_KEY = "email";
const DEFAULT_VALUE = "";

function subscribe(callback: () => void) {
  window.addEventListener("storage", callback);

  return () => window.removeEventListener("storage", callback);
}

export default function LocalStorageDemo() {
  const value = useSyncExternalStore(
    subscribe,
    () => localStorage.getItem(EMAIL_KEY) ?? DEFAULT_VALUE,
    () => DEFAULT_VALUE // Pour le Server-Side Rendering (SSR)
  );

  function updateEmailHandler() {
    const newEmail = faker.internet.email();
    localStorage.setItem(EMAIL_KEY, newEmail);
    window.dispatchEvent(new Event("storage"));
  }

  return (
    <div className="space-y-6 mt-8">
      <p>Adresse email : {value}</p>
      <Button onClick={updateEmailHandler}>Changer l&apos;email</Button>
    </div>
  );
}

Voici l’explication du code ci-dessus :

Voici les avantages :

Exemple avec l’API navigator.onLine

Pour illustrer davantage l’utilité de useSyncExternalStore, prenons un autre exemple : suivre l’état de connexion de l’utilisateur.

import React, { useSyncExternalStore } from "react";

function subscribe(callback: () => void) {
  window.addEventListener("online", callback);
  window.addEventListener("offline", callback);
  return () => {
    window.removeEventListener("online", callback);
    window.removeEventListener("offline", callback);
  };
}

export default function NetworkStatus() {
  const isOnline = useSyncExternalStore(subscribe, () => navigator.onLine);

  return (
    <div>
      <h1>{isOnline ? "Vous êtes en ligne" : "Vous êtes hors ligne"}</h1>
    </div>
  );
}

Voici l’explication du code ci-dessus :

Conclusion

Le hook useSyncExternalStore est un outil puissant pour synchroniser des données externes avec vos composants React de manière efficace et propre. Il permet de simplifier votre code tout en améliorant les performances de votre application.

Points Clés

Ressources supplémentaires

Commentaires