Si estás empezando a aprender React o ya llevas un tiempo usando esta librería, seguramente te has encontrado con algunos errores o advertencias relacionadas con funciones asíncronas, especialmente usando el hook useEffect
.
Cuando estaba aprendiendo la funcionalidad de este gancho, no podía entender la razón de usar el retorno en esta función, ya que en la mayoría de los casos no es necesario usarlo, y React funciona perfectamente sin él.
A medida que me familiaricé con la forma en que funciona React y el ciclo de vida de los componentes, comencé a notar que, en muchos casos, es demasiado importante usar el retorno en el gancho useEffect
, especialmente en los efectos secundarios.
Un efecto secundario puede ser obtener datos de un servidor remoto, leer o escribir en el almacenamiento local, configurar detectores de eventos o configurar una suscripción. Estos efectos secundarios pueden ocurrir cuando se hace clic en un botón, se envía un formulario o cuando se monta y desmonta un componente.
El gancho useEffect
de React permite que los componentes funcionales hagan cosas cuando se monta un componente o cuando cambian algunas propiedades o estados. Este gancho también permite limpiar cuando el componente está desmontado.
Manejar efectos secundarios en React es una tarea de mediana complejidad. Sin embargo, de vez en cuando, puede tener dificultades en la intersección del ciclo de vida del componente (representación inicial, montaje, uso, desmontaje) y el ciclo de vida de los efectos secundarios (iniciado, en curso, completo).
Una de esas dificultades es cuando un efecto secundario se completa e intenta actualizar el estado de un componente ya desmontado.
Esto provoca una advertencia de reacción como esta:
Las fugas de memoria en las aplicaciones React son principalmente el resultado de no cancelar las suscripciones realizadas cuando se montó un componente antes de desmontarlo.
Causan muchos problemas, incluyendo:
Por lo tanto, es necesario eliminar los problemas de pérdida de memoria.
Es una función del gancho useEffect
que nos permite detener los efectos secundarios que ya no necesitan ejecutarse antes de desmontar nuestro componente.
useEffect
está construido de tal manera que podemos devolver una función dentro de él y esta función de retorno es donde ocurre la limpieza.
Por ejemplo, el Componente A solicita a la API que obtenga una lista de productos, pero al realizar esa solicitud asíncrona, el Componente A se elimina del DOM (se desmonta). No es necesario completar esa solicitud asincrónica.
Entonces, como método de limpieza para mejorar su aplicación, puede limpiar (cancelar) la solicitud asincrónica para que no se complete.
useEffect
:
useEffect(() => { // Your effect return () => { // Cleanup } }, [input])
Hay diferentes formas de cancelar llamadas de solicitud de búsqueda, podemos usar fetch AbortController
o Axios AbortController.
Para usar AbortController
, debemos crear un controlador usando el constructor AbortController()
. Luego, cuando se inicia nuestra solicitud de recuperación, pasamos AbortSignal
como una opción dentro del objeto options
de la solicitud.
Esto asocia el controlador y la señal con la solicitud de búsqueda y nos permite cancelarla en cualquier momento usando AbortController.abort()
:
useEffect(() => { //create a controller let controller = new AbortController(); (async () => { try { const response = await fetch(API, { // connect the controller with the fetch request signal: controller.signal, }, ); // handle success setList(await response.json()); // remove the controller controller = null; } catch (e) { // Handle the error } })(); //aborts the request when the component umounts return () => controller?.abort(); },[]);
useEffect(() => { // create a controller const controller = new AbortController(); axios .get(API, { signal: controller.signal }) .then({data}) => { // handle success setList(data); }) .catch((err) => { // Handle the error }); //aborts the request when the component umounts return () => controller?.abort(); }, []);
Cuando usamos las funciones de temporizador setTimeout(callback, time)
, podemos borrarlas al desmontar usando la función especial clearTimeout(timerId)
.
useEffect(() => { let timerId = setTimeout(() => { // do something timerId = null; }, 3000); // cleanup the timmer when component unmout return () => clearTimeout(timerId); }, []);
Al igual que los tiempos de espera, setIntervals(callback, time)
tiene una función especial para limpiarlos con la función clearInterval(intervalId)
.
useEffect(() => { let intervalId = setInterval(() => { // do something like update the state }, 1000); // cleanup the timer when component unmout return () => clearInterval(interval); }, []);
La limpieza de los oyentes se realiza a través de window.removeEventListener
. La llamada removeEventListener
debe hacer referencia a la misma función en la llamada removeEventListener
para eliminar el oyente correctamente.
useEffect(() => { // function to add to EventListener const handleKeyUp= (event) => { switch (event.key) { case "Escape": setCollapsed(true); break; } } window.addEventListener("keyup", handleKeyUp); // cleanup the listener when component unmout return () => window.removeEventListener("keyup", handleKeyUp); }, []);
Cuando creas unsocket.close()
.
useEffect(() => { const ws = new WebSocket(url, protocols) // do what you want with the socket ws.onmessage = (event) => { setValue(JSON.parse(event.data)); }; // cleanup the web socket when component unmout return () => ws.close() }, [])
Hemos aprendido que algunos efectos secundarios requieren limpieza para evitar pérdidas de memoria y comportamientos innecesarios y no deseados. Debemos aprender cuándo y cómo usar la función de limpieza del gancho useEffect
para evitar estos problemas y optimizar las aplicaciones.
Recomiendo limpiar los efectos asincrónicos cuando se desmonta el componente. Además, si el efecto secundario asincrónico depende de los valores prop o state, considere también limpiarlos cuando se actualice el componente.
Espero que este artículo le haya resultado útil y que ahora pueda usar la función de limpieza correctamente.
Lee mas:
También publicado aquí .