So rufen Sie die Ladefunktion mit React useEffect nur einmal auf

205

Der Hook useEffect React führt bei jeder Änderung die übergebene Funktion aus. Dies kann so optimiert werden, dass es nur aufgerufen wird, wenn sich die gewünschten Eigenschaften ändern.

Was ist, wenn ich eine Initialisierungsfunktion von componentDidMountaufrufen und bei Änderungen nicht erneut aufrufen möchte ? Angenommen, ich möchte eine Entität laden, aber die Ladefunktion benötigt keine Daten von der Komponente. Wie können wir das mit dem useEffectHaken machen?

class MyComponent extends React.PureComponent {
    componentDidMount() {
        loadDataOnlyOnce();
    }
    render() { ... }
}

Mit Haken könnte dies so aussehen:

function MyComponent() {
    useEffect(() => {
        loadDataOnlyOnce(); // this will fire on every change :(
    }, [...???]);
    return (...);
}
Dávid Molnár
quelle

Antworten:

388

Wenn Sie die Funktion nur useEffectnach dem ersten Rendern ausführen möchten , können Sie ihr als zweites Argument ein leeres Array geben.

function MyComponent() {
  useEffect(() => {
    loadDataOnlyOnce();
  }, []);

  return <div> {/* ... */} </div>;
}
Tholle
quelle
27
Wenn Sie alternativ Parameter zum Abrufen der Daten verwenden (z. B. eine Benutzer-ID), können Sie die Benutzer-ID in diesem Array übergeben. Wenn sich die Komponente ändert, werden die Daten erneut abgerufen. Viele der Anwendungsfälle funktionieren so.
Trixn
4
yep ... mehr über das Überspringen ist hier dokumentiert: reactjs.org/docs/…
Melounek
Dies scheint die einfachste Antwort zu sein, aber ESLint beschwert sich ... siehe andere Antwort in diesem Thread stackoverflow.com/a/56767883/1550587
Simon Hutchison
85

TL; DR

useEffect(yourCallback, []) - löst den Rückruf erst nach dem ersten Rendern aus.

Ausführliche Erklärung

useEffectWird standardmäßig nach jedem Rendern der Komponente ausgeführt (wodurch ein Effekt verursacht wird).

Wenn useEffectSie Ihre Komponente platzieren, teilen Sie React mit, dass Sie den Rückruf als Effekt ausführen möchten. React führt den Effekt nach dem Rendern und nach dem Ausführen der DOM-Updates aus.

Wenn Sie nur einen Rückruf übergeben, wird der Rückruf nach jedem Rendern ausgeführt.

Wenn Sie ein zweites Argument (Array) übergeben, führt React den Rückruf nach dem ersten Rendern und jedes Mal aus, wenn eines der Elemente im Array geändert wird. Zum Beispiel beim Platzieren useEffect(() => console.log('hello'), [someVar, someOtherVar])- Der Rückruf wird nach dem ersten Rendern und nach jedem Rendern ausgeführt, das von someVaroder someOtherVargeändert wurde.

Wenn Sie dem zweiten Argument ein leeres Array übergeben, vergleicht React nach jedem Rendern des Arrays und stellt fest, dass nichts geändert wurde. Daher ruft der Rückruf erst nach dem ersten Rendern auf.

Edan Chetrit
quelle
68

useMountEffect-Hook

Das Ausführen einer Funktion nur einmal nach dem Mounten von Komponenten ist ein so häufiges Muster, dass ein eigener Hook gerechtfertigt ist, der Implementierungsdetails verbirgt.

const useMountEffect = (fun) => useEffect(fun, [])

Verwenden Sie es in jeder Funktionskomponente.

function MyComponent() {
    useMountEffect(function) // function will run only once after it has mounted. 
    return <div>...</div>;
}

Informationen zum useMountEffect-Hook

Bei Verwendung useEffectmit einem zweiten Array-Argument führt React den Rückruf nach dem Mounten (anfängliches Rendern) und nach dem Ändern der Werte im Array aus. Da wir ein leeres Array übergeben, wird es erst nach dem Mounten ausgeführt.

Ben Carp
quelle
19
Ich bevorzuge Ihre Antwort sehr, da die ESLint-Regel "React-Hooks / erschöpfende Deps" bei leeren Abhängigkeitslisten immer fehlschlägt. Und zum Beispiel wird die berühmte Vorlage zum Erstellen und Reagieren von Apps diese Regel durchsetzen.
Dynalon
1
Stimme voll und ganz @Dynalon zu. Dies sollte die akzeptierte Lösung sein, da sie die ESLint-Regel nicht beeinträchtigt
Mikado68
Danke @Dynalon und Mikado68 :-). Die Entscheidung ist ein Privileg des OP. Ich wurde über Ihre Kommentare informiert, das OP jedoch nicht. Sie können es ihm vorschlagen, indem Sie die Frage direkt kommentieren.
Ben Carp
2
Jetzt können Sie verwenden, useMountwenn Ihre Effektfunktion etwas von Requisiten benötigt, aber nie wieder ausgeführt werden muss, selbst wenn sich dieser Wert ohne Linterwarnung ändert: useEffect(()=>console.log(props.val),[])Fehlende Abhängigkeitswarnung, aber useMount(()=>console.log(props.val))keine Warnung, aber "funktioniert". Ich bin mir nicht sicher, ob es ein Problem mit dem gleichzeitigen Modus geben wird.
HMR
1
Ich mag dieses :) Gleicher Grund wie vorher angegeben; Die ESLint-Regel wird sich nicht über diese beschweren, und der Name ist leichter zu verstehen als ein leeres Array
Frexuz
20

Übergeben Sie ein leeres Array als zweites Argument an useEffect. Dies teilt React effektiv mit und zitiert die Dokumente :

Dies teilt React mit, dass Ihr Effekt nicht von Werten aus Requisiten oder Status abhängt und daher nie erneut ausgeführt werden muss.

Hier ist ein Ausschnitt, den Sie ausführen können, um zu zeigen, dass es funktioniert:

function App() {
  const [user, setUser] = React.useState(null);

  React.useEffect(() => {
    fetch('https://randomuser.me/api/')
      .then(results => results.json())
      .then(data => {
        setUser(data.results[0]);
      });
  }, []); // Pass empty array to only run once on mount.
  
  return <div>
    {user ? user.name.first : 'Loading...'}
  </div>;
}

ReactDOM.render(<App/>, document.getElementById('app'));
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>

<div id="app"></div>

Yangshun Tay
quelle
4

Ich definiere gerne eine mountFunktion, sie betrügt EsLint auf die gleiche Weise useMountund ich finde sie selbsterklärender.

const mount = () => {
  console.log('mounted')
  // ...

  const unmount = () => {
    console.log('unmounted')
    // ...
  }
  return unmount
}
useEffect(mount, [])
ökoologisch
quelle
0

Der Trick ist, dass useEffect einen zweiten Parameter verwendet.

Der zweite Parameter ist ein Array von Variablen, die die Komponente überprüft, um sicherzustellen, dass sie geändert wurde, bevor sie erneut gerendert wird. Sie können hier alle Requisiten und Zustände einfügen, gegen die Sie prüfen möchten.

Oder nichts sagen:

import React, { useEffect } from 'react';

function App() {
  useEffect(() => {

    // Run! Like go get some data from an API.

  }, []); //Empty array as second argument

  return (
    <div>
      {/* Do something with data. */}
    </div>
  );
}

Dadurch wird sichergestellt, dass useEffect nur einmal ausgeführt wird.

Anmerkung aus den Dokumenten:

Wenn Sie diese Optimierung verwenden, stellen Sie sicher, dass das Array alle Werte aus dem Komponentenbereich (z. B. Requisiten und Status) enthält, die sich im Laufe der Zeit ändern und vom Effekt verwendet werden. Andernfalls verweist Ihr Code auf veraltete Werte aus früheren Renderings.

Farrukh Malik
quelle
3
Wenn Sie buchstäblich aus CSS-Tricks kopieren / einfügen, können Sie zumindest Ihre Quelle gutschreiben. css-tricks.com/run-useeffect-only-once
burtyish