Published
- 4 min read
Buenas Prácticas con Hooks en React: Guía Definitiva

¡Hola! Hoy vamos a hablar de los hooks en React y cómo usarlos de la mejor manera posible. Si alguna vez te has preguntado por qué tus componentes se comportan de manera extraña o por qué tienes problemas con los efectos secundarios, este artículo es para ti.
Las Reglas de Oro de los Hooks
Antes de empezar, recordemos las dos reglas más importantes:
-
Solo usa hooks en el nivel superior
// ❌ Mal if (condicion) { useEffect(() => {}); } // ✅ Bien useEffect(() => { if (condicion) { // hacer algo } }, [condicion]);
-
Solo usa hooks en componentes de React o en otros hooks personalizados
// ❌ Mal function normalFunction() { const [count, setCount] = useState(0); } // ✅ Bien function MiComponente() { const [count, setCount] = useState(0); }
Organizando tus Hooks
1. Agrupa hooks relacionados
function MiComponente() {
// 1. Hooks de estado
const [usuario, setUsuario] = useState(null);
const [cargando, setCargando] = useState(false);
const [error, setError] = useState(null);
// 2. Hooks de contexto
const tema = useContext(TemaContext);
const auth = useContext(AuthContext);
// 3. Hooks de efectos
useEffect(() => {
// lógica de carga
}, []);
useEffect(() => {
// lógica de actualización
}, [usuario]);
// 4. Hooks de memoización
const datosProcesados = useMemo(() => {
return procesarDatos(usuario);
}, [usuario]);
const callback = useCallback(
() => {
// lógica del callback
},
[
/* dependencias */
]
);
// 5. Hooks de refs
const inputRef = useRef(null);
}
2. Extrae lógica compleja a hooks personalizados
// Hook personalizado para manejar datos de usuario
function useUsuario(userId) {
const [usuario, setUsuario] = useState(null);
const [cargando, setCargando] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function cargarUsuario() {
try {
const datos = await fetchUsuario(userId);
setUsuario(datos);
} catch (err) {
setError(err);
} finally {
setCargando(false);
}
}
cargarUsuario();
}, [userId]);
return { usuario, cargando, error };
}
// Uso en el componente
function PerfilUsuario({ userId }) {
const { usuario, cargando, error } = useUsuario(userId);
if (cargando) return <div>Cargando...</div>;
if (error) return <div>Error: {error.message}</div>;
return <div>Bienvenido, {usuario.nombre}!</div>;
}
Patrones Comunes y Soluciones
1. Manejo de suscripciones
function useSuscribirse(evento) {
useEffect(() => {
const suscripcion = evento.subscribe();
return () => suscripcion.unsubscribe();
}, [evento]);
}
2. Debounce y Throttle
function useDebounce(valor, delay) {
const [valorDebounceado, setValorDebounceado] = useState(valor);
useEffect(() => {
const timer = setTimeout(() => {
setValorDebounceado(valor);
}, delay);
return () => clearTimeout(timer);
}, [valor, delay]);
return valorDebounceado;
}
3. Formularios Controlados
function useFormulario(valoresIniciales) {
const [valores, setValores] = useState(valoresIniciales);
const handleChange = useCallback((e) => {
const { name, value } = e.target;
setValores((prev) => ({
...prev,
[name]: value,
}));
}, []);
const handleSubmit = useCallback(
(e) => {
e.preventDefault();
// lógica de envío
},
[valores]
);
return { valores, handleChange, handleSubmit };
}
Optimización de Rendimiento
1. Evita re-renders innecesarios
// ❌ Mal
function Componente() {
const [count, setCount] = useState(0);
const datos = procesarDatosComplejos(count); // Se recalcula en cada render
return <div>{datos}</div>;
}
// ✅ Bien
function Componente() {
const [count, setCount] = useState(0);
const datos = useMemo(() => procesarDatosComplejos(count), [count]);
return <div>{datos}</div>;
}
2. Memoiza callbacks
// ❌ Mal
function Componente() {
const handleClick = () => {
// lógica
};
return <button onClick={handleClick}>Click me</button>;
}
// ✅ Bien
function Componente() {
const handleClick = useCallback(
() => {
// lógica
},
[
/* dependencias */
]
);
return <button onClick={handleClick}>Click me</button>;
}
Tips y Trucos
-
Usa el hook de debug para desarrollo
function useDebug(nombre, valor) { useEffect(() => { console.log(`${nombre}:`, valor); }, [nombre, valor]); }
-
Crea hooks para lógica de UI
function useModal() { const [isOpen, setIsOpen] = useState(false); const open = useCallback(() => setIsOpen(true), []); const close = useCallback(() => setIsOpen(false), []); return { isOpen, open, close }; }
-
Combina hooks para funcionalidades complejas
function useAutenticacion() { const [usuario, setUsuario] = useState(null); const [cargando, setCargando] = useState(true); const [error, setError] = useState(null); const navigate = useNavigate(); const login = useCallback( async (credenciales) => { try { setCargando(true); const usuario = await autenticar(credenciales); setUsuario(usuario); navigate('/dashboard'); } catch (err) { setError(err); } finally { setCargando(false); } }, [navigate] ); return { usuario, cargando, error, login }; }
Errores Comunes y Cómo Evitarlos
-
Dependencias faltantes en useEffect
// ❌ Mal useEffect(() => { console.log(count); }, []); // Falta count en las dependencias // ✅ Bien useEffect(() => { console.log(count); }, [count]);
-
Estado inicial incorrecto
// ❌ Mal const [datos, setDatos] = useState(null); // ✅ Bien const [datos, setDatos] = useState({ cargando: true, error: null, data: null, });
-
Cleanup faltante en efectos
// ❌ Mal useEffect(() => { const suscripcion = evento.subscribe(); }, []); // ✅ Bien useEffect(() => { const suscripcion = evento.subscribe(); return () => suscripcion.unsubscribe(); }, []);
Conclusión
Los hooks son una herramienta poderosa en React, pero requieren práctica y conocimiento para usarlos correctamente. Recuerda:
- Mantén tus hooks simples y enfocados
- Extrae lógica compleja a hooks personalizados
- Optimiza el rendimiento cuando sea necesario
- Sigue las reglas de los hooks
- Usa TypeScript para mejor autocompletado y detección de errores