Lorsque vous lancez une promesse, la résolution de la promesse peut prendre quelques secondes et à ce moment-là, l'utilisateur peut avoir navigué vers un autre endroit de votre application. Ainsi, lorsque Promise résout setState
est exécuté sur un composant non monté et vous obtenez une erreur - comme dans votre cas. Cela peut également provoquer des fuites de mémoire.
C'est pourquoi il est préférable de déplacer une partie de votre logique asynchrone hors des composants.
Sinon, vous devrez annuler d'une manière ou d'une autre votre promesse . Alternativement - en dernier recours (c'est un anti-modèle) - vous pouvez conserver une variable pour vérifier si le composant est toujours monté:
componentDidMount(){
this.mounted = true;
this.props.fetchData().then((response) => {
if(this.mounted) {
this.setState({ data: response })
}
})
}
componentWillUnmount(){
this.mounted = false;
}
Je le soulignerai encore une fois - c'est un anti-modèle mais peut être suffisant dans votre cas (tout comme ils l'ont fait avec la Formik
mise en œuvre).
Une discussion similaire sur GitHub
ÉDITER:
C'est probablement ainsi que je résoudrais le même problème (n'ayant que React) avec Hooks :
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;
request.get(url)
.then(result => {
if (isMounted) {
setState(result);
}
});
return () => {
isMounted = false;
};
}, []);
return value;
}
OPTION B: Alternativement avec useRef
qui se comporte comme une propriété statique d'une classe, ce qui signifie qu'il ne rend pas le composant lorsque sa valeur change:
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;
}
function useIsMounted() {
const isMounted = React.useRef(true)
useEffect(() => {
return () => {
isMounted.current = false;
};
}, []);
return isMounted;
}
Exemple: https://codesandbox.io/s/86n1wq2z8