Comprendiendo los hooks personalizados de React: reutilización de lógica sin estado compartido
Aprenda qué son los hooks personalizados de React, cómo extraen e intercambian lógica con estado entre componentes, y qué errores comunes evitar al crearlos.
Introducción
¿Alguna vez te has encontrado escribiendo la misma combinación de useState y useEffect en tres componentes diferentes, cambiando solo los nombres de las variables cada vez? Casi todo desarrollador de React se topa con esto en algún momento. El código funciona bien, pero eso significa que la misma lógica termina duplicada en toda la base de código, y cada copia tiende a desviarse a medida que se modifica de forma independiente con el tiempo.
Esta es precisamente la situación para la cual se diseñaron los ganchos personalizados en React. La documentación de React sobre este tema explica que al trasladar el comportamiento de los componentes a una función dedicada y reutilizable, las partes separadas de una aplicación pueden compartir el mismo comportamiento con estado en lugar de copiar repetidamente la implementación subyacente. Esta sección del artículo explica qué son realmente los ganchos personalizados, cómo se comportan en código real, y las ventajas y desventajas que debe conocer antes de crear los suyos propios.
¿Qué son los ganchos personalizados de React?
En esencia, un gancho personalizado no es más que una función de JavaScript que sigue una regla estricta de nomenclatura: su nombre debe comenzar con use. Dentro de ella, se pueden llamar a otros ganchos como useState o useEffect, y devuelve los valores o funciones que necesite el componente que la llama. React en sí mismo no brinda a esta función ningún tratamiento especial durante su ejecución; el prefijo use es puramente una convención, pero es esencial, ya que permite a React aplicar correctamente las reglas de los ganchos y ayuda a otros desarrolladores a reconocer al instante para qué sirve la función.
Ganchos personalizados vs funciones regulares
Una función utilitaria estándar puede realizar muchas tareas útiles, pero no puede llamar a otros ganchos porque se encuentra fuera del mecanismo de renderizado de React. Un gancho personalizado no tiene esa restricción. Esa es precisamente su ventaja: puedes encapsular comportamientos con estado —como seguir un indicador de carga, escuchar un evento del navegador o cualquier cosa similar— en algo reutilizable que aún se integre perfectamente en el ciclo de vida de los componentes de React.
Cómo funcionan en la práctica los ganchos personalizados de React
Un ejemplo concreto aclara esto mucho más rápido que cualquier explicación abstracta.
Extraer la lógica de un componente
Imagina tres componentes no relacionados que cada uno necesita detectar si el navegador tiene actualmente una conexión a red. Sin un gancho compartido, cada uno de ellos tendría que crear su propio conjunto de useState y useEffect para monitorear eso:
function StatusBadge() {
const [isOnline, setIsOnline] = useState(navigator.onLine);
useEffect(() => {
const goOnline = () => setIsOnline(true);
const goOffline = () => setIsOnline(false);
window.addEventListener('online', goOnline);
window.addEventListener('offline', goOffline);
return () => {
window.removeEventListener('online', goOnline);
window.removeEventListener('offline', goOffline);
};
}, []);
return <span>{isOnline ? 'Online' : 'Offline'}</span>;
}
En su lugar, puedes trasladar esa lógica a un único gancho personalizado, y a partir de entonces cualquier componente que necesite el estado simplemente lo llama:
function useOnlineStatus() {
const [isOnline, setIsOnline] = useState(navigator.onLine);
useEffect(() => {
const goOnline = () => setIsOnline(true);
const goOffline = () => setIsOnline(false);
window.addEventListener('online', goOnline);
window.addEventListener('offline', goOffline);
return () => {
window.removeEventListener('online', goOnline);
window.removeEventListener('offline', goOffline);
};
}, []);
return isOnline;
}
// Usage in any component:
function StatusBadge() {
const isOnline = useOnlineStatus();
return <span>{isOnline ? 'Online' : 'Offline'}</span>;
}
Ninguno de los componentes tiene que configurar por sí mismo los receptores de eventos; cada uno solo solicita el valor actual mediante useOnlineStatus.
Compartir la lógica de estado sin compartir el estado
Este es un detalle que sorprende a muchos principiantes: un gancho personalizado comparte el comportamiento, no el estado en sí. Si dos componentes separados invocan useOnlineStatus, cada uno obtiene su propia copia privada de ese estado. Ejecutan la misma lógica, pero los valores reales que albergan en cada componente son completamente independientes; no existe ningún estado compartido o vinculado entre ellos.
Ventajas clave de usar ganchos personalizados en React
- Reutilización entre componentes: Una vez que la lógica se encuentra dentro de un hook, ningún componente de la aplicación necesita duplicar ni una sola línea para utilizarla, lo que garantiza que su comportamiento sea consistente en todos los lugares donde se emplee.
- Componentes más limpios y fáciles de leer: Al extraer la lógica con estado fuera del componente, el código restante queda prácticamente libre de problemas relacionados con la gestión de estado, lo que facilita enormemente su comprensión a quienes están empezando.
- Pruebas más sencillas de forma aislada: La lógica extraída puede probarse completamente por separado de cualquier componente que la utilice, lo que implica que solo es necesario verificarla una vez en lugar de volver a probarla indirectamente cada vez que cambie un componente consumidor.
use añadido— requiere una familiaridad real con los patrones subyacentes de React. Los equipos que desean que esto se gestione adecuadamente desde el principio a veces buscan fuera de su propio personal e incorporan desarrolladores especializados en ReactJS, cuya experiencia ayuda a que el diseño de los hooks se mantenga sólido incluso a medida que el proyecto crece.Errores comunes que evitar
Incluso los hooks escritos con buenas intenciones pueden fallar de varias maneras predecibles.
- Violación de las reglas de los hooks: Invocar un hook dentro de una condición, dentro de un bucle, o desde una función común en lugar de desde un componente u otro hook interfiere con la capacidad de React para mantener el estado consistente en cada renderizado. El resultado suele ser un error extraño e intermitente que es difícil rastrear hasta su causa.
- Amontonar demasiado en un solo hook: Incluir la validación de formularios, las solicitudes de red y la gestión del estado de la interfaz en un único hook personalizado hace que dicho hook sea más difícil de probar, reutilizar y comprender que si esas mismas responsabilidades estuvieran distribuidas en dos o tres hooks más pequeños y específicos.
useState merece convertirse en un hook independiente. Si una parte de la lógica solo se utiliza en un lugar, extraerla solo añade una capa adicional de indirección sin ningún beneficio real.Conclusión
Los ganchos personalizados en React no solo ayudan a evitar la repetición de código, sino que también funcionan como un mecanismo real para mantener una base de código en expansión coherente y consistente. Una vez que un equipo desarrolla el instinto para identificar la lógica que merece ser extraída, los componentes tienden a tener menos complejidad, los errores son más fáciles de localizar y el comportamiento se mantiene uniforme en toda la aplicación, en lugar de divergir lentamente entre componentes que deberían funcionar de la misma manera. A medida que las aplicaciones React siguen creciendo en escala y complejidad, entender cuándo y cómo crear un gancho personalizado sólido se está convirtiendo en una habilidad básica, y no algo reservado únicamente para desarrolladores avanzados.
Si su equipo está lidiando con un código repleto de lógica duplicada y desea darle una estructura real, podría valer la pena consultar a una empresa de desarrollo en React js que ya haya guiado refactores similares en otros proyectos a gran escala.
Lecturas relacionadas
- Tipado de React Hooks: useState, useEffect, useReducer y hooks personalizados — Aprenda cómo tipar correctamente useState, useEffect, useReducer y hooks personalizados en TypeScript, además de cuándo elegir TypeScript en lugar de JavaScript puro realmente compensa.