Ich denke, der Titel sagt alles. Die gelbe Warnung wird jedes Mal angezeigt, wenn ich eine Komponente abhebe, die noch abgerufen wird.
KonsoleWarnung: Eine nicht gemountete Komponente kann nicht aufgerufen
setState
(oderforceUpdate
) werden. Dies ist ein No-Op, aber ... Um dies zu beheben, kündigen Sie alle Abonnements und asynchronen Aufgaben in dercomponentWillUnmount
Methode.
constructor(props){
super(props);
this.state = {
isLoading: true,
dataSource: [{
name: 'loading...',
id: 'loading',
}]
}
}
componentDidMount(){
return fetch('LINK HERE')
.then((response) => response.json())
.then((responseJson) => {
this.setState({
isLoading: false,
dataSource: responseJson,
}, function(){
});
})
.catch((error) =>{
console.error(error);
});
}
Antworten:
Wenn Sie ein Versprechen auslösen, kann es einige Sekunden dauern, bis es aufgelöst wird. Zu diesem Zeitpunkt hat der Benutzer möglicherweise zu einem anderen Ort in Ihrer App navigiert. Wenn also Promise Resolves
setState
für eine nicht gemountete Komponente ausgeführt wird und Sie eine Fehlermeldung erhalten - genau wie in Ihrem Fall. Dies kann auch zu Speicherlecks führen.Aus diesem Grund ist es am besten, einen Teil Ihrer asynchronen Logik aus Komponenten zu entfernen.
Andernfalls müssen Sie Ihr Versprechen irgendwie stornieren . Alternativ können Sie als letzte Möglichkeit (es handelt sich um ein Antimuster) eine Variable behalten, um zu überprüfen, ob die Komponente noch bereitgestellt ist:
Ich werde das noch einmal betonen - dies ist ein Antimuster , kann aber in Ihrem Fall ausreichend sein (genau wie bei der
Formik
Implementierung).Eine ähnliche Diskussion auf GitHub
BEARBEITEN:
Dies ist wahrscheinlich, wie ich das gleiche Problem (mit nichts als Reagieren) mit Hooks lösen würde :
OPTION A:
OPTION B: Alternativ dazu
useRef
verhält es sich wie eine statische Eigenschaft einer Klasse, was bedeutet, dass keine Komponenten erneut gerendert werden, wenn sich der Wert ändert:Beispiel: https://codesandbox.io/s/86n1wq2z8
quelle
Die freundlichen Mitarbeiter von React empfehlen , Ihre Abrufe / Versprechen in ein stornierbares Versprechen zu packen. Obwohl in dieser Dokumentation keine Empfehlung enthalten ist, den Code beim Abrufen von der Klasse oder Funktion zu trennen, erscheint dies ratsam, da andere Klassen und Funktionen diese Funktionalität wahrscheinlich benötigen. Die Codeduplizierung ist ein Anti-Pattern und unabhängig vom verbleibenden Code sollte entsorgt oder storniert werden
componentWillUnmount()
. Gemäß React können Siecancel()
das eingewickelte Versprechen aufrufencomponentWillUnmount
, um zu vermeiden, dass der Status für eine nicht gemountete Komponente festgelegt wird.Der bereitgestellte Code würde ungefähr so aussehen wie diese Codefragmente, wenn wir React als Leitfaden verwenden:
---- BEARBEITEN ----
Ich habe festgestellt, dass die angegebene Antwort möglicherweise nicht ganz richtig ist, wenn ich dem Problem auf GitHub folge. Hier ist eine Version, die ich verwende und die für meine Zwecke funktioniert:
Die Idee war, dem Garbage Collector dabei zu helfen, Speicher freizugeben, indem die Funktion oder was auch immer Sie verwenden, auf null gesetzt wird.
quelle
Mit AbortController können Sie eine Abrufanforderung abbrechen.
Siehe auch: https://www.npmjs.com/package/abortcontroller-polyfill
quelle
Seit der Eröffnung des Beitrags wurde ein "Abbruch-Abruf" hinzugefügt. https://developers.google.com/web/updates/2017/09/abortable-fetch
(aus den Dokumenten :)
Das Controller + Signal-Manöver Treffen Sie den AbortController und AbortSignal:
Der Controller hat nur eine Methode:
controller.abort (); Wenn Sie dies tun, wird das Signal benachrichtigt:
Diese API wird vom DOM-Standard bereitgestellt, und das ist die gesamte API. Es ist absichtlich generisch, sodass es von anderen Webstandards und JavaScript-Bibliotheken verwendet werden kann.
So würden Sie beispielsweise nach 5 Sekunden ein Abruf-Timeout erstellen:
quelle
Der Kern dieser Warnung besteht darin, dass Ihre Komponente einen Verweis darauf enthält, der von einem ausstehenden Rückruf / Versprechen gehalten wird.
Um zu vermeiden, dass Ihr isMounted-Status wie im zweiten Muster erhalten bleibt (was Ihre Komponente am Leben erhält), schlägt die Reaktionswebsite vor , ein optionales Versprechen zu verwenden . Dieser Code scheint jedoch auch Ihr Objekt am Leben zu halten.
Stattdessen habe ich einen Abschluss mit einer verschachtelten gebundenen Funktion für setState verwendet.
Hier ist mein Konstruktor (Typoskript)…
quelle
this
Wenn ich "alle Abonnements kündigen und asynchron" muss, sende ich normalerweise etwas an redux in componentWillUnmount, um alle anderen Abonnenten zu informieren und bei Bedarf eine weitere Anfrage zur Kündigung an den Server zu senden
quelle
Ich denke, wenn es nicht notwendig ist, den Server über die Stornierung zu informieren, ist es am besten, nur die asynchrone / warten-Syntax zu verwenden (falls verfügbar).
quelle
Zusätzlich zu den Beispielen für stornierbare Versprechen in der akzeptierten Lösung kann es nützlich sein, einen
useAsyncCallback
Haken zu haben, der einen Anforderungsrückruf umschließt und ein stornierbares Versprechen zurückgibt. Die Idee ist die gleiche, aber mit einem Haken, der wie ein normaler funktioniertuseCallback
. Hier ist ein Beispiel für die Implementierung:quelle
Ich glaube, ich habe einen Weg gefunden, um das zu umgehen. Das Problem ist nicht so sehr das Abrufen selbst, sondern der setState, nachdem die Komponente verworfen wurde. Die Lösung bestand also darin,
this.state.isMounted
alsfalse
und dann wieder aufcomponentWillMount
wahr undcomponentWillUnmount
dann wieder auf falsch zu setzen. Dann nur nochif(this.state.isMounted)
den setState im Abruf. Wie so:quelle