Ist die Verwendung componentDidMount()
als asynchrone Funktion in React Native eine gute Praxis oder sollte ich sie vermeiden?
Ich muss einige Informationen AsyncStorage
abrufen, wenn die Komponente bereitgestellt wird, aber der einzige Weg, den ich kenne, um dies zu ermöglichen, besteht darin, die componentDidMount()
Funktion asynchron zu machen .
async componentDidMount() {
let auth = await this.getAuth();
if (auth)
this.checkAuth(auth);
}
Gibt es ein Problem damit und gibt es andere Lösungen für dieses Problem?
reactjs
asynchronous
react-native
Mirakurun
quelle
quelle
Antworten:
Beginnen wir damit, auf die Unterschiede hinzuweisen und festzustellen, wie dies zu Problemen führen kann.
Hier ist der Code für die asynchrone und "synchronisierte"
componentDidMount()
Lebenszyklusmethode:Wenn ich mir den Code ansehe, kann ich auf folgende Unterschiede hinweisen:
async
Schlüsselwörter: Im Typoskript ist dies lediglich eine Codemarkierung. Es macht 2 Dinge:Promise<void>
anstelle vonvoid
. Wenn Sie den Rückgabetyp explizit als nicht versprechend angeben (z. B. void), wird Typoskript einen Fehler an Sie ausspucken.await
Schlüsselwörtern innerhalb der Methode.void
nach geändertPromise<void>
async someMethod(): Promise<void> { await componentDidMount(); }
Sie können jetzt das
await
Schlüsselwort in der Methode verwenden und deren Ausführung vorübergehend anhalten. So was:Wie könnten sie nun Probleme verursachen?
async
Schlüsselwort ist absolut harmlos.Ich kann mir keine Situation vorstellen, in der Sie die
componentDidMount()
Methode aufrufen müssen, damit auch der RückgabetypPromise<void>
harmlos ist.Das Aufrufen einer Methode mit dem Rückgabetyp
Promise<void>
ohneawait
Schlüsselwort macht keinen Unterschied zum Aufrufen einer Methode mit dem Rückgabetyp vonvoid
.Da es nach
componentDidMount()
Verzögerung der Ausführung keine Lebenszyklusmethoden gibt, scheint dies ziemlich sicher zu sein. Aber es gibt eine Gotcha.Angenommen, das oben genannte wird
this.setState({users, questions});
nach 10 Sekunden ausgeführt. Mitten in der Verzögerungszeit ...this.setState({users: newerUsers, questions: newerQuestions});
... wurden erfolgreich ausgeführt und das DOM aktualisiert. Das Ergebnis war für Benutzer sichtbar. Die Uhr tickte weiter und es vergingen 10 Sekunden. Die Verzögerung
this.setState(...)
würde dann ausgeführt und das DOM würde erneut aktualisiert, diesmal mit alten Benutzern und alten Fragen. Das Ergebnis wäre auch für Benutzer sichtbar.=> Es ist ziemlich sicher (ich bin mir nicht sicher über 100%),
async
mitcomponentDidMount()
Methode zu verwenden. Ich bin ein großer Fan davon und habe bisher keine Probleme festgestellt, die mir zu viele Kopfschmerzen bereiten.quelle
setState()
immer mit einem geringen Risiko verbunden. Wir sollten vorsichtig vorgehen.isFetching: true
im Zustand einer Komponente zu verwenden. Ich habe dies nur mit Redux verwendet, aber ich nehme an, dass es mit der Nur-Reaktion-Statusverwaltung vollständig gültig ist. Obwohl es das Problem, dass derselbe Status irgendwo anders im Code aktualisiert wird, nicht wirklich löst ...isFetching
Flag-Lösung ziemlich häufig, insbesondere wenn wir einige Animationen im Front-End abspielen möchten, während wir auf die Back-End-Antwort warten (isFetching: true
).Update April 2020: Das Problem scheint in React 16.13.1 behoben zu sein (siehe dieses Sandbox-Beispiel) . Vielen Dank an @abernier für diesen Hinweis.
Ich habe einige Nachforschungen angestellt und einen wichtigen Unterschied festgestellt: React verarbeitet keine Fehler aus asynchronen Lebenszyklusmethoden.
Also, wenn Sie so etwas schreiben:
Dann wird Ihr Fehler von der Fehlergrenze erfasst , und Sie können ihn verarbeiten und eine ordnungsgemäße Meldung anzeigen.
Wenn wir den Code folgendermaßen ändern:
was dem entspricht:
dann wird Ihr Fehler lautlos verschluckt . Schande über dich, reagiere ...
Wie verarbeiten wir Fehler als? Der einzige Weg scheint ein expliziter Fang wie dieser zu sein:
oder so:
Wenn wir immer noch wollen, dass unser Fehler die Fehlergrenze erreicht, kann ich über den folgenden Trick nachdenken:
render
MethodeBeispiel:
quelle
Ihr Code ist in Ordnung und für mich sehr lesbar. Sehen Sie sich diesen Artikel von Dale Jefferson an, in dem er ein asynchrones
componentDidMount
Beispiel zeigt und auch wirklich gut aussieht.Aber einige Leute würden sagen, dass eine Person, die den Code liest, annehmen könnte, dass React etwas mit dem zurückgegebenen Versprechen macht.
Die Interpretation dieses Codes und ob es sich um eine gute Praxis handelt oder nicht, ist also sehr persönlich.
Wenn Sie eine andere Lösung wünschen, können Sie Versprechen verwenden . Beispielsweise:
quelle
async
Funktion mitawait
s im Inneren ...?(async () => { const data = await fetch('foo'); const result = await submitRequest({data}); console.log(result) })()
wofetch
undsubmitRequest
sind Funktionen, die Versprechen zurückgeben.Wenn Sie
componentDidMount
ohneasync
Schlüsselwort verwenden, sagt das Dokument Folgendes:Wenn Sie verwenden
async componentDidMount
, verlieren Sie diese Fähigkeit: Ein weiteres Rendern erfolgt, nachdem der Browser den Bildschirm aktualisiert hat. Aber imo, wenn Sie über die Verwendung von Async nachdenken, z. B. das Abrufen von Daten, können Sie nicht vermeiden, dass der Browser den Bildschirm zweimal aktualisiert. In einer anderen Welt ist es nicht möglich, componentDidMount zu PAUSE, bevor der Browser den Bildschirm aktualisiertquelle
Aktualisieren:
(Mein Build: React 16, Webpack 4, Babel 7):
Wenn Sie Babel 7 verwenden, werden Sie feststellen:
Mit diesem Muster ...
Sie werden auf den folgenden Fehler stoßen ...
Nicht erfasster ReferenceError: regeneratorRuntime ist nicht definiert
In diesem Fall müssen Sie babel-plugin-transform-runtime installieren
https://babeljs.io/docs/en/babel-plugin-transform-runtime.html
Wenn Sie aus irgendeinem Grund das obige Paket (babel-plugin-transform-runtime) nicht installieren möchten, sollten Sie sich an das Promise-Muster halten ...
quelle
Ich denke, es ist in Ordnung, solange Sie wissen, was Sie tun. Dies kann jedoch verwirrend sein, da
async componentDidMount()
es nach demcomponentWillUnmount
Ausführen und dem Abmelden der Komponente weiterhin ausgeführt werden kann .Möglicherweise möchten Sie auch sowohl synchrone als auch asynchrone Aufgaben im Inneren starten
componentDidMount
. WenncomponentDidMount
asynchron wäre, müssten Sie den gesamten synchronen Code vor dem ersten setzenawait
. Für jemanden ist es möglicherweise nicht offensichtlich, dass der Code vor dem erstenawait
synchron ausgeführt wird. In diesem Fall würde ich wahrscheinlichcomponentDidMount
synchron bleiben, aber Sync- und Async-Methoden aufrufen lassen.Ob Sie
async componentDidMount()
vs synccomponentDidMount()
aufrufenasync
Methoden, müssen Sie sicherstellen , dass aufzuräumen Sie Hörer oder Asynchron - Methoden , die noch ausgeführt werden, wenn die Komponente Aushänge.quelle
Tatsächlich ist das asynchrone Laden in ComponentDidMount ein empfohlenes Entwurfsmuster, da React von älteren Lebenszyklusmethoden (componentWillMount, componentWillReceiveProps, componentWillUpdate) zum asynchronen Rendern übergeht.
Dieser Blog-Beitrag ist sehr hilfreich, um zu erklären, warum dies sicher ist, und um Beispiele für das asynchrone Laden in ComponentDidMount bereitzustellen:
https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html
quelle
Ich benutze so etwas gerne
quelle