tuve este error antes
Advertencia: 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.
Este es mi useEffect donde recupero datos de firestore y elimina el error:
useEffect(async () => { let isMounted = true; const querySnapshot = await getDocs(collection(db, "product")); const arr = []; querySnapshot.forEach((doc) => { arr.push({ ...doc.data(), id: doc.id, }); if (isMounted) setProduct(arr); }); return () => { isMounted = false; }; }, []); ¿El useEffect bien o esto causará algún problema en el futuro? ¿Y estoy montando esto bien?
Esto se ve bien. Pero es mejor extraer la lógica de recuperación en una función separada en lugar de tener toda la lógica en el cuerpo de useEffect . Es fácil reutilizar la lógica para funciones como volver a intentar si la solicitud falla en el montaje.
yo haria algo asi...
isMounted como el efecto que se ejecutará cuando se monte el componente. // Re-usable logic for stuff like reload/retry const fetchProduct = async () => { const querySnapshot = await getDocs(collection(db, "product")); const arr = []; querySnapshot.forEach((doc) => { arr.push({ ...doc.data(), id: doc.id, }); }); setProduct(arr); // Moved this out of the loop to be run once. } useEffect(async () => { (async () => { await fetchProduct(); // await other async operations here. })(); // This immediately runs the func async. }, []);Mirando su código actual, llama a useEffect con una función async que usa await . Debido a que está utilizando una función async , la función de cancelación de suscripción que está devolviendo a useEffect está envuelta en una Promise en lugar de ser la devolución de llamada sin procesar en sí. Esto significa que useEffect nunca ve que el valor devuelto es una función de devolución de llamada a tiempo para que sea útil.
La solución a esto es asegurarse de que la función pasada a useEffect no sea async .
useEffect(() => { let isMounted = true; const doFetch = async () => { const querySnapshot = await getDocs(collection(db, "product")); const arr = []; querySnapshot.forEach((doc) => { arr.push({ ...doc.data(), id: doc.id, }); if (isMounted) setProduct(arr); }); }; doFetch() // start the async work .catch((err) => { if (!isMounted) return; // unmounted, ignore. // TODO: Handle errors in your component console.error("failed to fetch data", err); }); return () => { isMounted = false; }; }, []); Hay implementaciones de useAsyncEffect que le permiten omitir el setState() y useEffect() que está usando actualmente. Los he detallado en respuestas similares aquí y aquí .