Ich schlage vor, die Antwort von Dan Abramov (einem der Hauptbetreuer von React) hier zu lesen :
Ich denke, Sie machen es komplizierter als es sein muss.
function Example() {
const [data, dataSet] = useState<any>(null)
useEffect(() => {
async function fetchMyAPI() {
let response = await fetch('api/data')
response = await response.json()
dataSet(response)
}
fetchMyAPI()
}, [])
return <div>{JSON.stringify(data)}</div>
}
Längerfristig werden wir von diesem Muster abraten, da es die Rennbedingungen fördert. Zum Beispiel könnte zwischen dem Beginn und dem Ende Ihres Anrufs alles passieren, und Sie hätten neue Requisiten bekommen können. Stattdessen empfehlen wir Suspense für das Abrufen von Daten, das eher so aussieht
const response = MyAPIResource.read();
und keine Effekte. In der Zwischenzeit können Sie das asynchrone Material in eine separate Funktion verschieben und aufrufen.
Mehr über experimentelle Spannung können Sie hier lesen .
Wenn Sie Funktionen außerhalb mit eslint verwenden möchten.
function OutsideUsageExample() {
const [data, dataSet] = useState<any>(null)
const fetchMyAPI = useCallback(async () => {
let response = await fetch('api/data')
response = await response.json()
dataSet(response)
}, [])
useEffect(() => {
fetchMyAPI()
}, [fetchMyAPI])
return (
<div>
<div>data: {JSON.stringify(data)}</div>
<div>
<button onClick={fetchMyAPI}>manual fetch</button>
</div>
</div>
)
}
Mit useCallback useCallback . Sandkasten .
import React, { useState, useEffect, useCallback } from "react";
export default function App() {
const [counter, setCounter] = useState(1);
// if counter is changed, than fn will be updated with new counter value
const fn = useCallback(() => {
setCounter(counter + 1);
}, [counter]);
// if counter is changed, than fn will not be updated and counter will be always 1 inside fn
/*const fnBad = useCallback(() => {
setCounter(counter + 1);
}, []);*/
// if fn or counter is changed, than useEffect will rerun
useEffect(() => {
if (!(counter % 2)) return; // this will stop the loop if counter is not even
fn();
}, [fn, counter]);
// this will be infinite loop because fn is always changing with new counter value
/*useEffect(() => {
fn();
}, [fn]);*/
return (
<div>
<div>Counter is {counter}</div>
<button onClick={fn}>add +1 count</button>
</div>
);
}
useEffect(() => { let unmounted = false promise.then(res => { if (!unmounted) { setState(...) } }) return () => { unmounted = true } }, [])
eslint
bittet mich,fetchMyAPI()
als Abhängigkeit vonuseEffect
Wenn Sie eine asynchrone Funktion wie verwenden
Es gibt ein Versprechen zurück und
useEffect
erwartet nicht, dass die Rückruffunktion Versprechen zurückgibt , sondern erwartet, dass nichts zurückgegeben wird oder eine Funktion zurückgegeben wird.Als Problemumgehung für die Warnung können Sie eine selbstaufrufende asynchrone Funktion verwenden.
oder um es sauberer zu machen, können Sie eine Funktion definieren und sie dann aufrufen
Die zweite Lösung erleichtert das Lesen und hilft Ihnen beim Schreiben von Code zum Abbrechen früherer Anforderungen, wenn eine neue ausgelöst wird, oder zum Speichern der letzten Anforderungsantwort im Status
Arbeitscodesandbox
quelle
useEffect
Sie eine Funktion zurückgeben, um die Bereinigung durchzuführen, z. B. das Abbestellen von Ereignissen. Wenn Sie die asynchrone Funktion verwenden, können Sie nichts zurückgeben, dauseEffect
das Ergebnis nicht abgewartet wirdBis React einen besseren Weg bietet, können Sie einen Helfer erstellen
useEffectAsync.js
:Jetzt können Sie eine asynchrone Funktion übergeben:
quelle
useAsyncEffect
wie Sie sie geschrieben haben, kann leicht dazu führen, dass jemand denkt, wenn er eine Bereinigungsfunktion von ihrem asynchronen Effekt zurückgibt, wird sie zum richtigen Zeitpunkt ausgeführt. Dies könnte zu Speicherverlusten oder schlimmeren Fehlern führen. Daher haben wir uns dafür entschieden, die Benutzer dazu zu ermutigen, ihren Code umzugestalten, um die „Naht“ von asynchronen Funktionen, die mit dem Lebenszyklus von React interagieren, sichtbarer und das Verhalten des Codes infolgedessen hoffentlich bewusster und korrekter zu machen.Ich habe diese Frage durchgelesen und bin der Meinung, dass der beste Weg zur Implementierung von useEffect in den Antworten nicht erwähnt wird. Angenommen, Sie haben einen Netzwerkanruf und möchten etwas tun, sobald Sie die Antwort erhalten haben. Speichern Sie der Einfachheit halber die Netzwerkantwort in einer Statusvariablen. Möglicherweise möchten Sie action / reducer verwenden, um den Speicher mit der Netzwerkantwort zu aktualisieren.
Referenz => https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects
quelle
Versuchen
quelle
Für andere Leser kann der Fehler darauf zurückzuführen sein, dass die asynchrone Funktion keine Klammern enthält:
Berücksichtigung der asynchronen Funktion initData
Dieser Code führt zu Ihrem Fehler:
Aber dieser wird nicht:
(Beachten Sie die Klammern um initData ()
quelle
Hier kann der void-Operator verwendet werden.
Anstatt:
oder
du könntest schreiben:
Es ist etwas sauberer und hübscher.
Asynchrone Effekte können zu Speicherverlusten führen. Daher ist es wichtig, die Bereinigung der Komponente zu bereinigen. Im Falle eines Abrufs könnte dies folgendermaßen aussehen:
quelle