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 setStatefü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:
componentDidMount(){
this.mounted = true;
this.props.fetchData().then((response) => {
if(this.mounted) {
this.setState({ data: response })
}
})
}
componentWillUnmount(){
this.mounted = false;
}
Ich werde das noch einmal betonen - dies ist ein Antimuster , kann aber in Ihrem Fall ausreichend sein (genau wie bei der FormikImplementierung).
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:
import React, { useState, useEffect } from "react";
export default function Page() {
const value = usePromise("https://something.com/api/");
return (
<p>{value ? value : "fetching data..."}</p>
);
}
function usePromise(url) {
const [value, setState] = useState(null);
useEffect(() => {
let isMounted = true; // track whether component is mounted
request.get(url)
.then(result => {
if (isMounted) {
setState(result);
}
});
return () => {
// clean up
isMounted = false;
};
}, []); // only on "didMount"
return value;
}
OPTION B: Alternativ dazu useRefverhält es sich wie eine statische Eigenschaft einer Klasse, was bedeutet, dass keine Komponenten erneut gerendert werden, wenn sich der Wert ändert:
function usePromise2(url) {
const isMounted = React.useRef(true)
const [value, setState] = useState(null);
useEffect(() => {
return () => {
isMounted.current = false;
};
}, []);
useEffect(() => {
request.get(url)
.then(result => {
if (isMounted.current) {
setState(result);
}
});
}, []);
return value;
}
// or extract it to custom hook:
function useIsMounted() {
const isMounted = React.useRef(true)
useEffect(() => {
return () => {
isMounted.current = false;
};
}, []);
return isMounted; // returning "isMounted.current" wouldn't work because we would return unmutable primitive
}
Beispiel: https://codesandbox.io/s/86n1wq2z8