componentWillUnmount with React useEffect Hook

Lesezeit: 5 Minuten

Benutzer-Avatar
ChrisG

Wie kann die useEffect Hook (oder irgendein anderer Hook für diese Angelegenheit) zum Replizieren verwendet werden componentWillUnmount?

In einer traditionellen Klassenkomponente würde ich so etwas tun:

class Effect extends React.PureComponent {
    componentDidMount() { console.log("MOUNT", this.props); }
    componentWillUnmount() { console.log("UNMOUNT", this.props); }
    render() { return null; }
}

Mit dem useEffect Haken:

function Effect(props) {
  React.useEffect(() => {
    console.log("MOUNT", props);

    return () => console.log("UNMOUNT", props)
  }, []);

  return null;
}

(Vollständiges Beispiel: https://codesandbox.io/s/2oo7zqzx1n)

Dies funktioniert nicht, da die Funktion “Aufräumen” zurückgegeben wurde useEffect erfasst die Requisiten so, wie sie während des Mountens waren, und nicht den Status der Requisiten während des Unmountens.

Wie bekomme ich die neueste Version der Requisiten hinein? useEffect Aufräumen ohne Ausführen des Funktionskörpers (oder der Bereinigung) bei jedem Prop-Wechsel?

Eine ähnliche Frage betrifft nicht den Teil des Zugriffs auf die neuesten Requisiten.

Das reagieren docs Zustand:

Wenn Sie einen Effekt ausführen und ihn nur einmal bereinigen möchten (beim Mounten und Unmounten), können Sie ein leeres Array übergeben ([]) als zweites Argument. Dies teilt React mit, dass Ihr Effekt nicht von Werten von Props oder State abhängt, sodass er nie erneut ausgeführt werden muss.

In diesem Fall bin ich jedoch auf die Requisiten angewiesen … aber nur für den Reinigungsteil …

  • Was möchten Sie tun, wenn die Komponente ausgehängt ist? Es könnte einen anderen Weg geben, darüber zu gehen.

    – Thole

    13. März 2019 um 10:28 Uhr

  • Dies ist eher eine allgemeine Frage, da ich mich frage, ob es Fälle gibt, die noch nicht mit Hooks repliziert werden können. Ein konkretes Beispiel wäre jedoch das Speichern der Requisiten in localStorage, IndexDB oder ähnlichem beim Unmounten und das Zurücklesen beim Mounten. Ich denke nicht, dass dies bei jeder Prop-Änderung erfolgen sollte (z. B. Tastendruck (wenn wir Eingabefelder rendern)

    – ChrisG

    13. März 2019 um 10:31 Uhr

Benutzer-Avatar
Shubham Khatri

Sie können useRef verwenden und die zu verwendenden Requisiten innerhalb einer Closure speichern, z

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

DEMO

Ein besserer Weg ist jedoch, das zweite Argument an weiterzugeben useEffect damit die Bereinigung und Initialisierung bei jeder Änderung der gewünschten Requisiten erfolgt

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

  • Vielen Dank! Verwenden useRef funktioniert. Ich habe Ihre Technik auch auf das ursprüngliche Beispiel (auf das in der Frage verwiesen wird) hier angewendet: codesandbox.io/s/48w5m9pkwx zu Referenzzwecken.

    – ChrisG

    13. März 2019 um 10:39 Uhr

  • Obwohl dies die richtige Antwort ist … ist sie dennoch äußerst unergonomisch, insbesondere wenn Sie auch vom örtlichen Bundesland abhängig sind. Die Verwendung einer Klassenkomponente ist manchmal der bessere Weg.

    – hasufell

    21. November 2019 um 8:20 Uhr

  • Ich würde diese Lösung in einen benutzerdefinierten Hook umgestalten. Ich rufe meine an useStateEffectund der Hauptunterschied besteht darin, dass die Abhängigkeiten als Argumente an die Wirkungsfunktion übergeben werden, sodass Sie auf die aktuellen Werte zugreifen.

    – Tom

    30. Juli 2020 um 19:06 Uhr


  • Hier ist auch ein Link zur entsprechenden Dokumentation: Reactjs.org/docs/hooks-effect.html#effects-with-cleanup. Aus den Dokumenten: “Wenn Ihr Effekt eine Funktion zurückgibt, führt React sie aus, wenn es Zeit zum Aufräumen ist:”

    – Ethan

    19. Oktober 2020 um 17:43 Uhr


useLayoutEffect() ist Ihre Antwort im Jahr 2021

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

Dies entspricht ComponentWillUnmount.

In 99 % der Fälle möchten Sie useEffect verwenden, aber wenn Sie Aktionen ausführen möchten, bevor Sie das DOM unmounten, können Sie den von mir bereitgestellten Code verwenden.

  • Es tut mir leid, aber das löst nicht das von mir angesprochene Problem. Ich brauche Zugriff auf die Requisiten zum Zeitpunkt der Demontage und useLayoutEffect verhält sich nicht anders als useEffect im Hinblick darauf, nur bei Abhängigkeitsänderungen ausgeführt zu werden (das leere Array, das Sie übergeben haben). Daher hat Ihre Lösung beim Aushängen nur Zugriff auf die anfänglichen Props der FunctionComponent und nicht auf die “letzten Props”.

    – ChrisG

    1. April 2021 um 17:35 Uhr

  • Ahh Entschuldigung! Ich war an diesem Morgen bis 6 Uhr wach, also habe ich nicht gründlich gelesen, haha.

    – Simon L

    2. April 2021 um 8:27 Uhr

  • Ich habe die beiden obersten Fragen gelesen und darauf geantwortet. Ja, Sie müssen die Variable, auf die Sie sich konzentrieren möchten, in useRef einfügen, um direkten Zugriff auf die neuesten Änderungen zu erhalten. Die Rückgabefunktion useEffect() wird tatsächlich nach dem erneuten Rendern ausgeführt (was das DOM unzugänglich macht), während die Rückgabefunktion useLayoutEffect() vor dem erneuten Rendern ausgeführt wird (wodurch das DOM zugänglich wird). Dies war die sauberste Lösung, die ich gefunden hatte, und ich hatte gedacht, dass sie Ihrer ähnlich ist. Vielleicht hilft das in Zukunft trotzdem weiter 🙂

    – Simon L

    2. April 2021 um 8:38 Uhr

useLayoutEffect eignet sich hervorragend zum Bereinigen von eventListeners auf DOM-Knoten.

Ansonsten mit regulär useEffect ref.current wird null sein, wenn der Hook ausgelöst wird

Mehr zu Reaktionsdokumenten https://reactjs.org/docs/hooks-reference.html#uselayouteffect

  import React, { useLayoutEffect, useRef } from 'react';

  const audioRef = useRef(null);


  useLayoutEffect(() => {
    if (!audioRef.current) return;

    const progressEvent = (e) => {
      setProgress(audioRef.current.currentTime);
    };

    audioRef.current.addEventListener('timeupdate', progressEvent);

    return () => {
      try {
        audioRef.current.removeEventListener('timeupdate', progressEvent);
      } catch (e) {
        console.warn('could not removeEventListener on timeupdate');
      }
    };
  }, [audioRef.current]);



Hängen Sie ref an den Komponenten-DOM-Knoten an

<audio ref={audioRef} />

Benutzer-Avatar
Andrii Svirskyi

useEffect(() => {
  if (elements) {
    const cardNumberElement =
      elements.getElement('cardNumber') ||  // check if we already created an element
      elements.create('cardNumber', defaultInputStyles); // create if we did not
            
    cardNumberElement.mount('#numberInput');
  }
}, [elements]);

1186710cookie-checkcomponentWillUnmount with React useEffect Hook

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy