18
votes

Comment pouvons-nous implémenter componentWillUnmount en utilisant des hooks de réaction?

La méthode componentWillUnmount() est appelée immédiatement avant qu'un composant ne soit démonté et détruit. Si nous utilisons useEffect avec un tableau vide ([]) comme deuxième argument et 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. Ceci est fait pour des raisons de performances pour autant que je sache. Afin de ne pas retarder le rendu.

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

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

Mise à jour

Malheureusement, Effects with Cleanup s'exécute après avoir laissé le navigateur peindre. 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 clairement voir la séquence des 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 ne soit démonté à l'aide de hooks.

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. Pour plus de simplicité, nous n'avons pas de backend ni de 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 conservons 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 met en place un setInterval pour 1s.

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 met simplement les données dans le magasin (action distribue). Nous mettons notre rappel dans l'instruction return useEffect pour forcer save à 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 rapide que 1s). Étant donné que le nettoyage de notre premier composant sera appelé après le re-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 dans son état local.

Si nous mettons notre callback 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 hooks?


2 commentaires

Veuillez lireEffets avec nettoyage . Ceci a la réponse.


@ArupRakshit, je viens de relire ça et ça ne répond toujours pas à la question. La fonction de retour sur un hook s'exécute APRÈS le démontage, comment exécuter du code avec des hooks AVANT le démontage?


6 Réponses :


25
votes

componentWillUnmount peut être simulé en renvoyant une fonction à l'intérieur du hook useEffect . La fonction retournée sera appelée juste avant chaque nouveau rendu du composant. Strictement parlant, c'est la même chose mais vous devriez être capable de simuler n'importe quel comportement que vous voulez en utilisant cela.

useEffect(() => {
  const unsubscribe = api.createSubscription()
  return () => unsubscribe()
}, [])

Mise à jour

Ce qui précède s'exécutera à chaque fois qu'il y aura un rerender. Cependant, pour simuler le comportement uniquement lors du montage et du démontage (c.-à-d. ComponentDidMount et componentWillUnmount). useEffect prend un deuxième argument qui doit être un tableau vide.

useEffect(() => {
  const unsubscribe = api.createSubscription()
  return () => unsubscribe()
})

Voir une explication plus détaillée de la même questionici .


5 commentaires

Il semble que c'est ce que la plupart des gens pensent. Mais en réalité, la fonction retournée n'est pas appelée avant le rendu. Il est appelé après un nouveau rendu.


Pour moi, il se déclenche à chaque rendu de composant (pas uniquement au démontage). J'utilise React 16.12.0.


useEffect prend un deuxième argument dans ce cas, pour simuler une passe de démontage dans un tableau vide, par exemple useEffect (() => {...}, [])


Dans le cas où j'utilise le tableau vide, que dois-je faire si je veux lire un état mais qu'il continue de se plaindre que je devrais l'ajouter au tableau de dépendances?


Bien que cela résout clairement les problèmes de certaines personnes, cela ne répond pas à la question. La fonction de retour sur un hook s'exécute APRÈS le démontage, comment exécuter du code avec des hooks AVANT le démontage?



0
votes

Peu importe que la fonction retournée par useEffect soit appelée avant ou après le useEffect du composant: vous avez toujours accès aux états valables à 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 vers le parent.


3 commentaires

Merci, mais la question n'est pas de savoir comment accéder aux valeurs. J'ai mis à jour ma question avec un scénario plus détaillé pour la rendre plus claire. J'ai tendance à penser que les hooks ne peuvent pas faire cela et dans ce cas, nous avons toujours besoin de composants de classe.


@georgy ne pouvez-vous pas élever l'état au parent?


Oui, c'est une option. Mais je préférerais utiliser un composant de classe avec componentWillUnmount() place. L'augmentation de l'état rend le code plus difficile à maintenir à mon avis.



0
votes

Les documents ReactJS sur les hooks spécifient ceci:

Les effets peuvent également éventuellement spécifier 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.


1 commentaires

Oui, mais la question est d'appeler du code avant que le composant ne soit démonté, pas après



4
votes

La question ici est de savoir comment exécuter du code avec des hooks AVANT le démontage? La fonction de retour avec hooks s'exécute APRÈS le démontage et bien que cela ne fasse pas de différence dans la plupart des cas d'utilisation, il y en a là où c'est une différence critique.

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

Espérons que cela changera à l'avenir


0 commentaires

-1
votes

Après quelques recherches, j'ai constaté que - vous pouviez toujours accomplir cela. Peu compliqué mais devrait fonctionner.

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

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

DEMO

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

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>;
}


0 commentaires

0
votes

Depuis l'introduction du hook useLayoutEffect , vous pouvez maintenant faire

useLayoutEffect(() => () => {
  // Your code here.
}, [])

pour simuler componentWillUnmount . Cela s'exécute pendant le démontage, mais avant que l'élément ait réellement quitté la page.


0 commentaires