Hooks reagieren useEffect () bereinigen nur für componentWillUnmount?

83

Lassen Sie mich das Ergebnis dieses Codes erklären, damit ich mein Problem leicht stellen kann.

const ForExample = () => {
    const [name, setName] = useState('');
    const [username, setUsername] = useState('');

    useEffect(() => {
        console.log('effect');
        console.log({
            name,
            username
        });

        return () => {
            console.log('cleaned up');
            console.log({
                name,
                username
            });
        };
    }, [username]);

    const handleName = e => {
        const { value } = e.target;

        setName(value);
    };

    const handleUsername = e => {
        const { value } = e.target;

        setUsername(value);
    };

    return (
        <div>
            <div>
                <input value={name} onChange={handleName} />
                <input value={username} onChange={handleUsername} />
            </div>
            <div>
                <div>
                    <span>{name}</span>
                </div>
                <div>
                    <span>{username}</span>
                </div>
            </div>
        </div>
    );
};

Wenn die ForExample componentReittiere aktiviert sind, wird der Effekt protokolliert. Dies hängt mit dem zusammen componentDidMount().

Und wenn ich die Namenseingabe ändere, werden sowohl "Effekt" als auch "Bereinigt" protokolliert. Umgekehrt wird keine Nachricht protokolliert, wenn ich die Eingabe des Benutzernamens ändere, seit ich [username]den zweiten Parameter von hinzugefügt habe useEffect(). Dies hängt mit dem zusammencomponentDidUpdate()

Zuletzt wird beim ForExample componentAufheben der Bereitstellung "bereinigt" protokolliert. Dies hängt mit dem zusammen componentWillUnmount().

Wir alle wissen das.

Zusammenfassend wird "bereinigt" immer dann aufgerufen, wenn die Komponente neu gerendert wird (einschließlich Unmount).

Wenn ich möchte, dass diese Komponente nur für den Moment "bereinigt" protokolliert wird, in dem sie nicht gemountet ist, muss ich nur den zweiten Parameter von useEffect()in ändern [].

Wenn ich jedoch zu wechsle [username], []wird ForExample componentdie componentDidUpdate()Eingabe für den Namen nicht mehr implementiert .

Was ich tun möchte, ist, dass die Komponente sowohl componentDidUpdate()nur für die Namenseingabe als auch unterstützt componentWillUnmount(). (Protokollierung 'bereinigt' nur für den Moment, in dem die Komponente abgemeldet wird)

koo
quelle
4
Sie könnten 2 verschiedene Effekte haben. Eine, die ein Array mit einem usernamezweiten Argument enthält, und eine, die ein leeres Array als zweites Argument erhält.
Tholle
@Tholle Meinst du, ich muss 2 separate useEffect () -Methoden erstellen?
Koo
1
Ja, das ist eine Möglichkeit.
Tholle
1
@Tholle Ich dachte, es würde von der letzten useEffect () -Methode überschrieben. Ich werde es versuchen. Danke
koo
2
Toll! Bitte. Es hängt davon ab, was die Bereinigung tun soll. 2 separate Effekte sind keine schlechte Lösung.
Tholle

Antworten:

81

Da die Bereinigung nicht von der abhängig ist username, können Sie die Bereinigung in einem separaten Bereich useEffectablegen, dem als zweites Argument ein leeres Array zugewiesen wird.

Beispiel

const { useState, useEffect } = React;

const ForExample = () => {
  const [name, setName] = useState("");
  const [username, setUsername] = useState("");

  useEffect(
    () => {
      console.log("effect");
    },
    [username]
  );

  useEffect(() => {
    return () => {
      console.log("cleaned up");
    };
  }, []);

  const handleName = e => {
    const { value } = e.target;

    setName(value);
  };

  const handleUsername = e => {
    const { value } = e.target;

    setUsername(value);
  };

  return (
    <div>
      <div>
        <input value={name} onChange={handleName} />
        <input value={username} onChange={handleUsername} />
      </div>
      <div>
        <div>
          <span>{name}</span>
        </div>
        <div>
          <span>{username}</span>
        </div>
      </div>
    </div>
  );
};

function App() {
  const [shouldRender, setShouldRender] = useState(true);

  useEffect(() => {
    setTimeout(() => {
      setShouldRender(false);
    }, 5000);
  }, []);

  return shouldRender ? <ForExample /> : null;
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>

Tholle
quelle
schönes und sauberes Beispiel. Ich frage mich aber. Kann ich einen Verwendungseffekt bei geänderter Navigation auslösen oder muss ich ihn im Komponentenbaum nach oben verschieben? Denn wenn ich gerade Ihren "aufgeräumten" useEffect einfüge, sehe ich diesen Auslöser nicht.
Fabian Bosler
113

Sie können mehr als einen useEffect verwenden

Wenn meine Variable beispielsweise data1 ist, kann ich all dies in meiner Komponente verwenden

useEffect( () => console.log("mount"), [] );
useEffect( () => console.log("will update data1"), [ data1 ] );
useEffect( () => console.log("will update any") );
useEffect( () => () => console.log("will update data1 or unmount"), [ data1 ] );
useEffect( () => () => console.log("unmount"), [] );
Mehran Motiee
quelle
4
Was ist der Unterschied zwischen dem ersten und dem letzten useEffects? Der erste useEffect wird auf dem willmount oder didmount aufgerufen . Der letzte useEffect wurde zurückgegeben. Rückruffunktion mit leerem Array Warum? Können Sie die einzelnen UseEffect-Anwendungsfälle erläutern, wann und wie wir sie verwenden können?
Siluveru Kiran Kumar
3
@siluverukirankumar Der Rückgabewert (Funktion) eines Rückrufs wird beim Zerstören aufgerufen (Unmount-Ereignis). Aus diesem Grund ist das letzte Beispiel ein HOC, das die Funktion sofort zurückgibt. Der zweite Parameter ist, wo React nach Änderungen suchen würde, um diesen Hook erneut auszuführen. Wenn es sich um ein leeres Array handelt, wird es nur einmal ausgeführt.
Georgy
3
Danke @Georgy hat es bekommen, die letzte VerwendungEffect gibt Rückruf zurück, der nicht klar gesehen wird
siluveru kiran kumar
2
Wenn Sie also einen useEffect-Hook erstellen und eine Funktion zurückgeben, wird der Code vor der zurückgegebenen Funktion als componentDidMount ausgeführt und der Code in der zurückgegebenen Funktion wird für componentWillUnmount aufgerufen. Es ist ein wenig verwirrend, also stelle sicher, dass ich es richtig verstehe. useEffect (() => {// Code zum Ausführen auf Mount ... return () => {// Code zum Ausführen von Dismount}}) Ist das richtig?
Maiya
Ich schlage vor, überreagiert zu lesen.io/a-complete-guide-to-useeffect Über Haken in Lebenszyklen nachzudenken ist nicht wirklich süß
moto
2
function LegoComponent() {

  const [lego, setLegos] = React.useState([])

  React.useEffect(() => {
    let isSubscribed = true
    fetchLegos().then( legos=> {
      if (isSubscribed) {
        setLegos(legos)
      }
    })
    return () => isSubscribed = false
  }, []);

  return (
    <ul>
    {legos.map(lego=> <li>{lego}</li>)}
    </ul>
  )
}

Im obigen Code gibt die Funktion fetchLegos ein Versprechen zurück. Wir können das Versprechen „stornieren“, indem wir eine Bedingung für den Anwendungsbereich haben, die verhindert, dass die App den Status festlegt, nachdem die Komponente nicht bereitgestellt wurde.

Warnung: Es kann keine Aktualisierung des Reaktionsstatus für eine nicht gemountete Komponente durchgeführt werden. Dies ist ein No-Op, weist jedoch auf einen Speicherverlust in Ihrer Anwendung hin. Brechen Sie zum Beheben alle Abonnements und asynchronen Aufgaben in einer useEffect-Bereinigungsfunktion ab.

Daniel Yap
quelle
0

useEffect sind in ihrem eigenen Bereich isoliert und werden entsprechend gerendert. Bild von https://reactjs.org/docs/hooks-custom.html

Geben Sie hier die Bildbeschreibung ein

Peter Anthony Duot
quelle
Ein Link zu einer Lösung ist willkommen, aber stellen Sie sicher, dass Ihre Antwort ohne sie nützlich ist: Fügen Sie dem Link einen Kontext hinzu, damit Ihre Mitbenutzer eine Vorstellung davon haben, was es ist und warum es dort ist, und zitieren Sie dann den relevantesten Teil der Seite, die Sie verwenden. erneutes Verknüpfen mit, falls die Zielseite nicht verfügbar ist. Antworten, die kaum mehr als ein Link sind, können gelöscht werden .
10огдан Оп .р
0

Anstatt zu viele komplizierte Funktionen und Methoden zu erstellen, erstelle ich einen Ereignis-Listener und lasse das Ein- und Aushängen automatisch für mich durchführen, ohne dass ich mich manuell darum kümmern muss. Hier ist ein Beispiel.

//componentDidMount
useEffect( () => {

    window.addEventListener("load",  pageLoad);

    //component will unmount
    return () => {
       
        window.removeEventListener("load", pageLoad);
    }

 });

Jetzt, da dieser Teil fertig ist, führe ich einfach alles aus, was ich will, über die Funktion pageLoad wie folgt.

const pageLoad = () =>{
console.log(I was mounted and unmounted automatically :D)}
jerryurenaa
quelle