javascript - Cancelando el Async de useEffect con TypeScript, la manera correcta
Tengo este ejemplo simple que me está dando problemas:
useEffect(() => {
axios.get(...).then(...).catch(...)
}, [props.foo])
advertencia: no se puede realizar una actualización del estado de React en un componente desmontado
He investigado un poco y este es más comprensible. A TypeScript no le parece bien ese enfoque ya que useEffect debería devolver void.
useEffect(() => {
let isSubscribed = true
axios.get(...).then(...).catch(...)
return () => (isSubscribed = false)
}, [props.foo])
TypeScript:
/**
* Accepts a function that contains imperative, possibly effectful code.
*
* @param effect Imperative function that can return a cleanup function
* @param deps If present, effect will only activate if the values in the list change.
*
* @version 16.8.0
* @see https://reactjs.org/docs/hooks-reference.html#useeffect
*/
function useEffect(effect: EffectCallback, deps?: DependencyList): void;
¿Cómo implementar un isSubscribed en mi useEffect con TS?
Gracias.
Respuesta #1
useEffect en sí devuelve void, pero la función proporcionada a useEffect está tipada como EffectCallback. Esto se define como:
// NOTE: callbacks are _only_ allowed to return either void, or a destructor.
// The destructor is itself only allowed to return void.
type EffectCallback = () => (void | (() => void | undefined));
Fuente
Esto significa que tu función de efecto puede en realidad devolver una función, la cual debe devolver void o undefined.
Ahora puedes resolver tu problema para evitar llamar a setState con la variable isSubscribed. Pero otra manera (quizás mejor) es cancelar la solicitud directamente.
useEffect(() => {
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.get('...', { cancelToken: source.token }).then(/**/).catch(e => {
if (axios.isCancel(thrown)) {
console.log('Request canceled', thrown.message);
} else {/* handle error */}
});
return () => source.cancel();
}, [props.foo])
Esto también está documentado en el README.
El problema con tu código actual es que tu función destructor devuelve el booleano isSubscribed. En lugar de devolverlo, simplemente coloca la asignación dentro del cuerpo de la función:
return () => {
isSubscribed = false;
}
