Quando si attiva una promessa, potrebbero essere necessari alcuni secondi prima che si risolva e a quel punto l'utente potrebbe essere passato a un'altra posizione nella tua app. Quindi, quando Promise si risolve setState
viene eseguito su un componente non montato e viene visualizzato un errore, proprio come nel tuo caso. Ciò può anche causare perdite di memoria.
Ecco perché è meglio spostare parte della logica asincrona dai componenti.
Altrimenti, dovrai in qualche modo annullare la tua Promessa . In alternativa, come ultima risorsa tecnica (è un antipattern), puoi mantenere una variabile per verificare se il componente è ancora montato:
componentDidMount(){
this.mounted = true;
this.props.fetchData().then((response) => {
if(this.mounted) {
this.setState({ data: response })
}
})
}
componentWillUnmount(){
this.mounted = false;
}
Lo sottolineerò di nuovo: questo è un antipattern ma potrebbe essere sufficiente nel tuo caso (proprio come hanno fatto con l' Formik
implementazione).
Una discussione simile su GitHub
MODIFICARE:
Questo è probabilmente come risolverei lo stesso problema (non avendo nient'altro che React) con gli Hooks :
OPZIONE 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;
}
OPZIONE B: In alternativa, useRef
che si comporta come una proprietà statica di una classe, il che significa che non esegue il rendering del componente quando il suo valore cambia:
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;
}
Esempio: https://codesandbox.io/s/86n1wq2z8