En términos simples, useEffect permite ejecutar código después de que el componente se haya renderizado, y también ofrece una manera de limpiar esos efectos cuando el componente se desmonta o cuando cambian las dependencias especificadas.
import React, { useEffect } from 'react';
function MiComponente() {
useEffect(() => {
console.log('Componente montado');
// Cleanup opcional que se ejecuta cuando el componente se desmonta
return () => {
console.log('Componente desmontado');
};
}, []); // Array de dependencias vacío: el efecto solo se ejecuta en el montaje y desmontaje
return <div>Hola, soy un componente con useEffect</div>;
}
La estructura básica del useEffect es la siguiente:
1. Función de efecto: La primera parte de useEffect es una función que contiene el código que se ejecutará después de que React haya renderizado el componente.
2. Array de dependencias: La segunda parte (opcional) es un array que define cuándo debe volver a ejecutarse el efecto. Este array de dependencias le dice a React qué valores debe observar para determinar si debe ejecutar nuevamente el efecto.
useEffect
1. Montaje y Desmontaje: Cuando se pasa un array de dependencias vacío ([]), el efecto se ejecuta solo una vez, similar a componentDidMount en los componentes de clase. Si el efecto tiene un retorno, esa función se ejecuta cuando el componente se desmonta, equivalente a componentWillUnmount.
2. Dependencias: Cuando se proporciona un array con variables, el efecto se ejecuta cada vez que alguna de esas variables cambie. Esto permite controlar cuándo React debe volver a ejecutar el efecto.
3. Actualización: Si se omite el array de dependencias, el efecto se ejecuta después de cada renderizado del componente, es decir, después de cada cambio de estado o de props. Esto no es ideal en la mayoría de los casos, ya que puede provocar comportamientos no deseados y afectar el rendimiento.
A continuación, se presentan algunos casos de uso comunes de useEffect en los componentes de React.
Una de las aplicaciones más comunes de useEffect es hacer solicitudes a APIs. En este caso, se usa para cargar datos cuando el componente se monta.
import React, { useState, useEffect } from 'react';
function DatosUsuario({ userId }) {
const [userData, setUserData] = useState(null);
useEffect(() => {
// Función asíncrona para obtener datos
const fetchData = async () => {
const response = await fetch(`https://jsonplaceholder.typicode.com/users/${userId}`);
const data = await response.json();
setUserData(data);
};
fetchData();
}, [userId]); // El efecto se ejecuta cada vez que cambia el `userId`
return (
<div>
{userData ? (
<div>
<h2>{userData.name}</h2>
<p>Email: {userData.email}</p>
</div>
) : (
'Cargando...'
)}
</div>
);
}
En este ejemplo:
userData para almacenar los datos del usuario.
useEffect se usa para hacer una llamada a la API cuando el componente se monta o cuando cambia el valor de userId.
[userId] asegura que el efecto se ejecute solo cuando userId cambie.
Puedes usar useEffect para suscribirte a eventos y luego limpiar la suscripción cuando el componente se desmonta.
import React, { useEffect, useState } from 'react';
function VentanaSize() {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const handleResize = () => setWidth(window.innerWidth);
window.addEventListener('resize', handleResize);
// Cleanup para remover el listener cuando el componente se desmonte
return () => {
window.removeEventListener('resize', handleResize);
};
}, []); // El efecto solo se ejecuta una vez cuando el componente se monta
return <p>Ancho de la ventana: {width}px</p>;
}
En este ejemplo:
useEffect para añadir un listener de eventos resize de la ventana.
window.removeEventListener) elimina el listener para evitar fugas de memoria.
useEffect no puede ser directamente una función asíncrona (async), se pueden definir funciones asíncronas dentro de él y llamarlas. Otra opción es usar then y catch para manejar promesas.
Al igual que otros hooks en React, useEffect sigue algunas reglas:
1. Llamar a hooks en la parte superior del componente: useEffect y otros hooks deben ser llamados en la parte superior de un componente funcional, y nunca dentro de condicionales o bucles. Esto asegura que React mantenga el estado de los hooks correctamente.
2. No llamar a hooks dentro de funciones ordinarias: Los hooks deben ser utilizados exclusivamente en componentes funcionales o en custom hooks.
Antes de la introducción de hooks, los componentes de clase de React usaban métodos de ciclo de vida como componentDidMount, componentDidUpdate y componentWillUnmount para manejar efectos secundarios. La introducción de useEffect simplificó este proceso al combinar estas funcionalidades en un solo hook:
componentDidMount y componentDidUpdate → useEffect
componentWillUnmount → Función de limpieza dentro de useEffect
useEffect
1. Evitar Dependencias Innecesarias: Asegúrate de definir correctamente el array de dependencias para evitar que el efecto se ejecute innecesariamente. React puede mostrar advertencias si las dependencias están mal definidas.
2. Memorización de funciones: Si pasas funciones al efecto, usa useCallback para evitar crear nuevas instancias de la función en cada renderizado.
useEffect(() => {
const id = setInterval(() => {
setTime(new Date());
}, 1000);
return () => clearInterval(id);
}, []); // El array vacío asegura que el intervalo se configure solo una vez
En este ejemplo, setInterval se configura una sola vez en el montaje, y clearInterval limpia el intervalo en el desmontaje.
useEffect es una herramienta poderosa para manejar efectos secundarios en los componentes funcionales de React. Comprender cómo y cuándo utilizar useEffect es crucial para crear aplicaciones React eficientes y mantenibles. Al controlar correctamente el ciclo de vida de los efectos y definir las dependencias adecuadas, puedes crear aplicaciones reactivas y optimizadas sin las complejidades de los componentes de clase.
Jorge García
Fullstack developer