me sale este error:
No se puede realizar una actualización de estado de React en un componente desmontado. Esto no es operativo, pero indica una pérdida de memoria en su aplicación. Para solucionarlo, cancele todas las suscripciones y tareas asincrónicas en una función de limpieza useEffect.
cuando se inicia la obtención de datos y el componente se desmontó, pero la función intenta actualizar el estado del componente desmontado.
¿Cuál es la mejor manera de resolver esto?
default function Test() { const [notSeenAmount, setNotSeenAmount] = useState(false) useEffect(() => { let timer = setInterval(updateNotSeenAmount, 2000) return () => clearInterval(timer) }, []) async function updateNotSeenAmount() { let data // here i fetch data setNotSeenAmount(data) // here is problem. If component was unmounted, i get error. } async function anotherFunction() { updateNotSeenAmount() //it can trigger update too } return <button onClick={updateNotSeenAmount}>Push me</button> //update can be triggered manually }
La solución más sencilla es utilizar una variable local que realice un seguimiento de si el componente está montado o no. Este es un patrón común con el enfoque basado en clases. Aquí hay un ejemplo que lo implementa con ganchos:
function Example() { const [text, setText] = React.useState("waiting..."); React.useEffect(() => { let isCancelled = false; simulateSlowNetworkRequest().then(() => { if (!isCancelled) { setText("done!"); } }); return () => { isCancelled = true; }; }, []); return <h2>{text}</h2>; }
Aquí hay una alternativa con useRef
(ver más abajo). Tenga en cuenta que con una lista de dependencias, esta solución no funcionará. El valor de la referencia se mantendrá verdadero después del primer renderizado. En ese caso, la primera solución es más apropiada.
function Example() { const isCancelled = React.useRef(false); const [text, setText] = React.useState("waiting..."); React.useEffect(() => { fetch(); return () => { isCancelled.current = true; }; }, []); function fetch() { simulateSlowNetworkRequest().then(() => { if (!isCancelled.current) { setText("done!"); } }); } return <h2>{text}</h2>; }
Puedes encontrar más información sobre este patrón dentro de este artículo . Aquí hay un problema dentro del proyecto React en GitHub que muestra esta solución.
Si está obteniendo datos de axios (usando ganchos) y el error aún ocurre, simplemente ajuste el setter dentro de la condición
let isRendered = useRef(false); useEffect(() => { isRendered = true; axios .get("/sample/api") .then(res => { if (isRendered) { setState(res.data); } return null; }) .catch(err => console.log(err)); return () => { isRendered = false; }; }, []);
Aquí hay un ejemplo de CodeSandBox
Las otras respuestas funcionan, por supuesto, solo quería compartir una solución que se me ocurrió. Construí este gancho que funciona como useState de React, pero solo establecerá State si el componente está montado. ¡Lo encuentro más elegante porque no tienes que perder el tiempo con una variable isMounted en tu componente!
npm install use-state-if-mounted
const [count, setCount] = useStateIfMounted(0);
Puede encontrar documentación más avanzada en la página npm del gancho.