Eine kurze Diskussion über die Fallstricke der React UseEffect-Abschließung

Eine kurze Diskussion über die Fallstricke der React UseEffect-Abschließung

Problemcode

Schauen Sie sich den Code eines durch useEffect verursachten Closure-Problems an.

const btn = useRef();
const [v, setV] = useState('');

useEffect(() => {
    let clickHandle = () => {
        Konsole.log('v:', v);
    }
    btn.current.addEventListener('klicken', KlickHandle)
    
    zurückgeben () => {
        btn.removeEventListener('click', KlickHandle)
    }
}, []);
    
const inputHandle = e => {
    setV(e.Ziel.Wert)
}

zurückkehren (
        <>
            <Eingabewert={v} beiÄnderung={inputHandle} />
            <button ref={btn} >Testen</button>
        </>
    )

Das Abhängigkeitsarray von useEffect ist leer, sodass der interne Code nur einmal ausgeführt wird, nachdem das Rendern der Seite abgeschlossen ist, und noch einmal, wenn die Seite zerstört wird. Geben Sie zu diesem Zeitpunkt ein beliebiges Zeichen in das Eingabefeld ein und klicken Sie auf die Testschaltfläche. Die Ausgabe ist leer. Unabhängig davon, welche Zeichen Sie anschließend eingeben und erneut auf die Testschaltfläche klicken, ist das Ausgabeergebnis immer noch leer.

Warum passiert das? Tatsächlich wird es durch die Schließung verursacht.

Ursache

Der Gültigkeitsbereich einer Funktion wird bei der Definition der Funktion festgelegt.

Beim Registrieren eines Klickereignisses für btn ist der Umfang wie folgt:

Die zugängliche freie Variable v ist zu diesem Zeitpunkt noch null. Wenn ein Klickereignis ausgelöst wird, wird die Klick-Rückruffunktion ausgeführt. Zu diesem Zeitpunkt wird zuerst der Ausführungskontext erstellt und die Bereichskette in den Ausführungskontext kopiert.

  • Wenn Sie keine Zeichen in das Eingabefeld eingeben, ist das v, das Sie erhalten, wenn Sie darauf klicken, immer noch das ursprüngliche v
  • Wenn ein Zeichen in das Eingabefeld eingegeben wird, wird setV aufgerufen, um den Status zu ändern, die Seite löst das Rendern aus und der interne Code der Komponente wird erneut ausgeführt, wobei ein v erneut deklariert wird und v nicht mehr das ursprüngliche v ist. Das v im Rahmen des Klickereignisses ist immer noch das alte v. Dies sind zwei verschiedene v

Szene generieren

  • Ereignisbindung. Im Beispielcode wird das Ereignis beispielsweise nur einmal gebunden, nachdem die erste Darstellung der Seite abgeschlossen ist. Wenn beispielsweise echarts verwendet wird, wird die Instanz von echarts in useEffect abgerufen und das Ereignis wird gebunden.
  • Timer. Das Registrieren eines Timers nach dem Laden der Seite führt ebenfalls zu einem solchen Abschlussproblem in der Funktion innerhalb des Timers.

Lösung

Hier sind 5 Lösungen für dieses Schließungsproblem:

1. Ändern Sie v direkt durch Zuweisung und umschließen Sie die Methode, die v ändert, mit useCallback

Umschließen Sie die Methode, die v ändert, mit useCallback. Die von useCallback umschlossene Funktion wird zwischengespeichert. Da das Array der Abhängigkeiten leer ist, ist das hier durch direkte Zuweisung geänderte v das alte v. Diese Methode wird nicht empfohlen, da setState die offiziell empfohlene Methode zum Ändern des Status ist. Hier wird setV immer noch nur verwendet, um ein erneutes Rendern auszulösen.

// Ändern Sie die Deklaration von v von const in var, um eine direkte Änderung zu ermöglichen var [v, setV] = useState('');

const inputHandle = useCallback(e => {
    let { Wert } = e.Ziel
    v = Wert
    setzeV(Wert)
}, [])

2. Fügen Sie v zu den Abhängigkeiten von useEffect hinzu

Dies ist möglicherweise die erste Lösung, die den meisten Leuten in den Sinn kommt. Da v alt ist, warum wird das Ereignis nicht bei jeder Aktualisierung von v neu registriert? Dies führt jedoch bei jeder Aktualisierung von v zu einer Neuregistrierung. Theoretisch wird ein Ereignis, das nur einmal registriert werden muss, mehrfach registriert.

3. Vermeiden Sie die erneute Deklaration von v

Deklarieren Sie eine Variable anstelle von v mit let oder var und ändern Sie die Variable direkt, anstatt das Rendern mit setState-bezogenen Funktionen auszulösen. Auf diese Weise wird die Variable nicht erneut deklariert und der „neueste“ Wert kann in der Klick-Callbackfunktion abgerufen werden. Diese Methode wird jedoch nicht empfohlen. Für dieses Beispiel zeigt die Eingabekomponente immer einen leeren Wert an, da kein erneutes Rendern erfolgt, was nicht der erwarteten Operation entspricht.

4. Verwenden Sie useRef anstelle von useState

const btn = useRef();
const vRef = useRef('');
const [v, setV] = useStat('');

useEffect(() => {
    let clickHandle = () => {
        console.log('v:', vRef.current);
    }
    btn.current.addEventListener('klicken', KlickHandle)
    
    zurückgeben () => {
        btn.removeEventListener('click', KlickHandle)
    }
}, []);

const inputHandle = e => {
    let { Wert } = e.Ziel
    vRef.current = Wert
    setzeV(Wert)
}

zurückkehren (
        <>
            <Eingabewert={v} beiÄnderung={inputHandle} />
            <button ref={btn} >Testen</button>
        </>
    )

Der Grund, warum die useRef-Lösung effektiv ist, liegt darin, dass jede Eingabeänderung die aktuelle Eigenschaft des vRef-Objekts ändert und vRef immer dieses vRef ist, auch wenn es erneut gerendert wird. Da vRef ein Objekt ist, ist der Wert der im Stapelspeicher gespeicherten Variablen die Adresse des Objekts im Heap-Speicher, die nur eine Referenz ist. Es wird nur eine bestimmte Eigenschaft des Objekts geändert, und die Referenz ändert sich nicht. Die Scope-Kette im Click-Event greift also immer auf dieselbe vRef zu.

5. Ersetzen Sie v durch einen Objekttyp

Tatsächlich ist es genau wie bei der Verwendung von useRef so, dass, solange es sich um ein Objekt handelt, das Ändern nur eines bestimmten Attributs nicht die vom Status gezeigte Adresse ändert.

Code-Adresse

Klicken Sie hier, um den Testcode anzuzeigen

Dies ist das Ende dieses Artikels über die Fallstricke von React UseEffect Closure. Weitere relevante Inhalte zu React UseEffect Closure finden Sie in den vorherigen Artikeln von 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, dass jeder 123WORDPRESS.COM in Zukunft unterstützen wird!

Das könnte Sie auch interessieren:
  • React useEffect verstehen und verwenden
  • Der Unterschied zwischen useEffect und useLayoutEffect in React

<<:  Linux weist eine Sicherheitslücke bei der Rechteausweitung bei Sudo auf, jeder Benutzer kann auch Root-Befehle ausführen

>>:  So geben Sie Parametervariablen extern im Docker an

Artikel empfehlen

Installieren Sie CentOS 7 auf VMware14 – Grafik-Tutorial

Einführung in CentOS CentOS ist eine Linux-Distri...

Zusammenfassung der englischen Namen chinesischer Schriftarten

Wenn Sie in CSS die Eigenschaft „font-family“ ver...

Beispiele und bewährte Vorgehensweisen für die Seitennummerierung

<br />Struktur und Hierarchie reduzieren die...

So fügen Sie bedingte Ausdrücke zu Aggregatfunktionen in MySql hinzu

MySQL-Filterungs-Timing von Where-Bedingungen und...

Detailliertes Installationstutorial für Windows 10 + MySQL 8.0.11 Zip

Vorbereiten: Downloadadresse für das MySQL 8.0 Wi...

Schritte zur Einführung von PWA in ein Vue-Projekt

Inhaltsverzeichnis 1. Abhängigkeiten installieren...