Por favor, no considere esto como un duplicado. He buscado en muchos blogs y cosas pero no he llegado a la solución.
En primer lugar, mi pregunta es '¿cómo resolver el cambio de estado de reacción en un error de componente desmontado y cancelar una llamada de función asíncrona que se importa dentro del enlace useEffect?'
Sé que puede resolver el error ' estado cambiado en un componente desmontado ' usando la función de limpieza en useEffect. En los casos de llamada asíncrona dentro del gancho useEffect, puede borrar el tiempo de espera, usar el token de cancelación para Axios, crear el estado [isMounted] para marcar el estado montado/desmontado, etc. Entonces, al menos, sé cómo ocultar la advertencia de reacción
Sin embargo, mi jefe no solo quiere ocultar la advertencia, sino también cancelar la solicitud asíncrona. Aquí está la versión simplificada del código.
import { fetchFunction } from '../../../somewhereInTheDir'; function Page() { const [data, setData] = useState([]); const [isMounted, setIsMounted] = useState(true); async function fetchData() { try { const data = await fetchFunction(someUri); setData(data); } catch (error) { console.warn(error); } } useEffect(() => { if(isMounted) { fetchData(ENDPOINT); } return () => { setIsMounted(false); } }) }
El estado isMounted
oculta la advertencia. Así que no veo nada en la consola, lo cual es una buena señal. Pero este código no bloquea ni cancela los datos que provienen del punto final cuando el componente de la página está desmontado. Y no puede usar estrategias como poner el token de cancelación en el encabezado http, porque fetchFunction
es externo.
PD. mi jefe dijo que usar el estado isMounted
como si fuera una variable de JavaScript podría ser un antipatrón de React, ya que el cambio de estado de React conduce a una nueva representación. ¿Hay una mejor manera de ocultar la advertencia sin usar el estado isMounted
?
Puede probar este enfoque en su lugar. Realice un seguimiento del estado montado en el gancho mismo, así como la función condicional setState.
También es importante que incluya la matriz de dependencia vacía, de lo contrario, su componente llamará al gancho en cada renderizado.
import { fetchFunction } from '../../../somewhereInTheDir'; function Page() { const [data, setData] = useState([]); const [isMounted, setIsMounted] = useState(true); async function fetchData() { try { return await fetchFunction(someUri); } catch (error) { console.warn(error); } } useEffect(() => { // <- you can't change this to async let mounted = true // Variant with Promise fetchData(ENDPOINT).then(data => { if (mounted) setData(data); }) // Variant with async/await (async () => { const data = await fetchData(ENDPOINT) if (mounted) setData(data); }()) return () => { mounted = false } }, []) // <- empty dependency array is important here }
El siguiente artículo presenta algunos otros métodos sobre cómo manejar el estado de montaje, incluso si usa múltiples ganchos useEffect, etc.
https://www.benmvp.com/blog/handling-async-react-component-effects-after-unmount/
Con respecto al último párrafo de su pregunta, puede usar referencias en lugar de estado.
const isMounted = useRef(false) useEffect(() => { isMounted.current = true return () => isMounted.current=false }, [])