web-dev-qa-db-fra.com

Comment pouvons-nous implémenter componentWillUnmount en utilisant des hooks React?

La méthode componentWillUnmount() est invoquée immédiatement avant qu'un composant soit démonté et détruit. Si nous utilisons useEffect avec un tableau vide ([]) comme deuxième argument et que nous mettons notre fonction dans l'instruction return, elle sera exécutée après le démontage du composant et même après le montage d'un autre composant. Cela est fait pour des raisons de performance pour autant que je comprends. Afin de ne pas retarder le rendu.

La question est donc - comment pouvons-nous appeler une fonction à l'aide de crochets avant qu'un composant ne soit démonté?

Ce que j'essaie de faire est une application qui enregistre les entrées de l'utilisateur pendant qu'il tape (sans soumettre de formulaire). J'utilise setInterval pour enregistrer le texte mis à jour toutes les N secondes. Et je dois forcer la sauvegarde des mises à jour avant que le composant ne se démonte. Je ne veux pas utiliser le routeur Prompt by react avant de naviguer. Ceci est une application électronique. J'apprécie toute réflexion ou conseil sur la façon de mettre en œuvre une telle fonctionnalité.

Mise à jour

Malheureusement, Effects with Cleanup exécuté après avoir laissé le navigateur Paint. Plus de détails peuvent être trouvés ici: Alors qu'en est-il du nettoyage? . Cela signifie essentiellement que le nettoyage est exécuté après le démontage d'un composant et que ce n'est pas la même chose que l'exécution de code dans componentWillUnmount(). Je peux voir clairement la séquence d'appels si je mets des instructions console.log dans le code de nettoyage et dans un autre composant. La question est de savoir si nous pouvons exécuter du code avant qu'un composant soit démonté à l'aide de crochets.

Update2

Comme je peux le voir, je devrais mieux décrire mon cas d'utilisation. Imaginons une application théorique qui conserve ses données dans un magasin Redux. Et nous avons deux composants avec certaines formes. Par souci de simplicité, nous n'avons ni backend ni logique asynchrone. Nous utilisons uniquement le magasin Redux comme stockage de données.

Nous ne voulons pas mettre à jour le magasin Redux à chaque frappe. Nous gardons donc les valeurs réelles dans l'état du composant local que nous initialisons avec les valeurs du magasin lors du montage d'un composant. Nous créons également un effet qui définit un setInterval pour 1 s.

Nous avons le processus suivant. Un utilisateur tape quelque chose. Les mises à jour sont stockées dans l'état du composant local jusqu'à ce que notre rappel setInterval soit appelé. Le rappel place simplement les données dans le magasin (action de répartition). Nous mettons notre rappel dans l'instruction de retour useEffect pour forcer la sauvegarde à stocker lorsque le composant est démonté car nous voulons enregistrer les données à stocker dans ce cas dès que possible.

Le problème survient lorsqu'un utilisateur tape quelque chose dans le premier composant et passe immédiatement au deuxième composant (plus vite que 1 s). Étant donné que le nettoyage de notre premier composant sera appelé après le nouveau rendu, notre magasin ne sera pas mis à jour avant le montage du deuxième composant. Et à cause de cela, le deuxième composant obtiendra des valeurs obsolètes à son état local.

Si nous mettons notre rappel dans componentWillUnmount() il sera appelé avant le démontage et le magasin sera mis à jour avant le prochain montage du composant. Alors pouvons-nous implémenter cela en utilisant des crochets?

15
Georgy Nemtsov

Après avoir fait un peu de recherche à ce sujet, je suis arrivé à la conclusion que les hooks ne fournissent tout simplement pas d'alternative à componentWillUnmount. Donc, si vous avez un cas d'utilisation qui en a besoin, qui est principalement pour moi au moins, des bibliothèques d'intégration non React, il vous suffit de le faire à l'ancienne et d'utiliser un composant.

Espérons que cela changera à l'avenir

1
David Bradshaw

Après un peu de recherche, j'ai découvert que - vous pouviez toujours accomplir cela. Un peu délicat mais devrait fonctionner.

Vous pouvez utiliser useRef et stocker les accessoires à utiliser dans une fermeture comme la méthode de rappel return useEffect

function Home(props) {
  const val = React.useRef();
  React.useEffect(
    () => {
      val.current = props;
    },
    [props]
  );
  React.useEffect(() => {
    return () => {
      console.log(props, val.current);
    };
  }, []);
  return <div>Home</div>;
}

DÉMO

Cependant, une meilleure façon est de passer le deuxième argument à useEffect pour que le nettoyage et l'initialisation se produisent sur tout changement d'accessoires souhaités

React.useEffect(() => {
  return () => {
    console.log(props.current);
  };
}, [props.current]);
0
pritam

Les documents ReactJS sur les hooks spécifient ceci:

Les effets peuvent également spécifier en option comment "nettoyer" après eux en renvoyant une fonction.

Ainsi, toute fonction que vous retournez dans votre hook useEffect sera exécutée lorsque le composant sera démonté, ainsi qu'avant de réexécuter l'effet en raison d'un rendu ultérieur.

0
pritam

Peu importe que la fonction retournée de useEffect soit appelée avant ou après le démontage du composant: Vous avez toujours accès aux états valeureux à travers la fermeture:

  const [input, setInput] = useState(() => Store.retrieveInput());

  useEffect(() => {
    return () => Store.storeInput(input); // < you can access "input" here, even if the component unmounted already
  }, []);

Si vous ne gérez pas l'entrée dans l'état des composants, toute votre structure est cassée et doit être modifiée pour gérer l'état au bon endroit. Dans votre cas, vous devez soulever l'état d'entrée partagé des composants au parent.

0
Jonas Wilms