
React Hooks: Guía Definitiva para Desarrolladores Modernos
Domina los React Hooks. Aprende useState, useEffect, useContext, useReducer y cómo crear tus propios custom hooks.
React Hooks: Guía Definitiva para Desarrolladores Modernos
Los React Hooks revolucionaron completamente la forma en que escribimos componentes React, eliminando la necesidad de componentes de clase y permitiendo reutilizar lógica de estado de manera más elegante y eficiente. Esta guía definitiva te enseña todo lo que necesitas saber sobre React Hooks, desde useState y useEffect hasta la creación de custom hooks avanzados.
¿Qué son los React Hooks y por qué son importantes?
Los React Hooks son funciones especiales que te permiten "engancharte" (hook into) características de React desde componentes funcionales. Introducidos en React 16.8, los Hooks eliminaron la complejidad de los componentes de clase y abrieron un nuevo paradigma para escribir componentes React.
Antes de los Hooks (React Class Components)
- Sintaxis compleja con this.state y this.setState
- Lógica de ciclo de vida dispersa en múltiples métodos
- Dificultad para reutilizar lógica entre componentes
- Mayor tamaño de bundle
Los Hooks resuelven todos estos problemas proporcionando una forma más simple, modular y reutilizable de manejar estado y efectos secundarios en componentes funcionales.
useState Hook - Agregando estado a componentes funcionales
useState es el hook más fundamental y el que usarás con mayor frecuencia. Permite agregar estado a componentes funcionales sin necesidad de convertirlos en componentes de clase.
Sintaxis básica de useState
import { useState } from 'react';
function Counter() {
// Desestructuramos [valor, función para actualizar]
const [count, setCount] = useState(0);
return (
<>
<p>Contador: {count}</p>
<button onClick={() => setCount(count + 1)}>
Incrementar
</button>
</>
);
}
Parámetros y retorno de useState
- Parámetro: Valor inicial del estado (puede ser cualquier tipo: number, string, object, array)
- Retorna: Array con [estado actual, función para actualizar]
- Función actualizadora: Puede recibir un valor o una función (para acceder al estado anterior)
Actualizar estado basado en estado anterior
// ✅ Correcto - usando función
const [count, setCount] = useState(0);
setCount(prevCount => prevCount + 1);
// ❌ Incorrecto - pueden perderse actualizaciones
setCount(count + 1);
setCount(count + 1);
Casos de uso avanzados de useState
// Estado con objeto complejo
const [user, setUser] = useState({ name: '', email: '' });
// Actualizar propiedad específica
setUser({ ...user, name: 'Juan' });
// Estado con array
const [todos, setTodos] = useState([]);
setTodos([...todos, { id: 1, title: 'Tarea nueva' }]);
// Función de inicialización (lazy initialization)
const [state, setState] = useState(() => {
console.log('Inicialización costosa');
return computeExpensiveValue();
});
useEffect Hook - Manejando efectos secundarios
useEffect permite ejecutar código cuando el componente se monta, actualiza o desmonta. Reemplaza los métodos de ciclo de vida componentDidMount, componentDidUpdate y componentWillUnmount.
Sintaxis básica de useEffect
import { useEffect } from 'react';
function DataFetcher() {
const [data, setData] = useState(null);
useEffect(() => {
// Este código se ejecuta después de cada render
console.log('Componente montado o actualizado');
// Cleanup function (opcional)
return () => {
console.log('Limpiando recursos');
};
}); // Sin dependency array - se ejecuta siempre
}
Dependency Array - Controlando cuándo se ejecuta useEffect
// Se ejecuta solo al montar el componente
useEffect(() => {
console.log('Montado');
}, []);
// Se ejecuta cuando userId cambia
useEffect(() => {
fetchUserData(userId);
}, [userId]);
// Se ejecuta después de cada render
useEffect(() => {
console.log('Render completado');
});
Patrones comunes con useEffect
Fetching de datos
useEffect(() => {
let isMounted = true;
const fetchData = async () => {
const response = await fetch('/api/users');
const data = await response.json();
if (isMounted) {
setUsers(data);
}
};
fetchData();
return () => {
isMounted = false; // Evita memory leaks
};
}, []);
Event listeners
useEffect(() => {
const handleResize = () => {
setWidth(window.innerWidth);
};
window.addEventListener('resize', handleResize);
// Cleanup: remover listener
return () => window.removeEventListener('resize', handleResize);
}, []);
Hooks adicionales - La caja de herramientas de React
useContext - Compartir datos sin prop drilling
useContext te permite acceder a valores del Context sin necesidad de anidar componentes Consumer.
const ThemeContext = React.createContext('light');
function ThemedComponent() {
const theme = useContext(ThemeContext);
return <div className={theme}>Contenido</div>;
}
useReducer - Estado complejo con múltiples acciones
Para estado más complejo que useState, useReducer proporciona un patrón Redux-like.
const initialState = { count: 0 };
function reducer(state, action) {
switch(action.type) {
case 'INCREMENT':
return { count: state.count + 1 };
case 'DECREMENT':
return { count: state.count - 1 };
default:
return state;
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
<p>Contador: {state.count}</p>
<button onClick={() => dispatch({ type: 'INCREMENT' })}>+</button>
<button onClick={() => dispatch({ type: 'DECREMENT' })}>-</button>
</>
);
}
useCallback - Memorizar funciones
Evita crear nuevas funciones en cada render, importante para optimización con React.memo.
const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]); // Solo se recrea si a o b cambian
useMemo - Memorizar valores computados
Evita cálculos costosos innecesarios.
const memoizedValue = useMemo(() => {
return expensiveCalculation(a, b);
}, [a, b]);
useRef - Referencias directas al DOM
Accede directamente a elementos del DOM sin afectar el re-render.
function TextInput() {
const inputRef = useRef(null);
const focusInput = () => {
inputRef.current.focus();
};
return (
<>
<input ref={inputRef} />
<button onClick={focusInput}>Enfocar</button>
</>
);
}
Creando Custom Hooks - Lógica reutilizable
Los Custom Hooks son funciones que usan otros hooks. Permiten extraer y compartir lógica entre componentes de manera elegante.
Reglas para crear Custom Hooks
- El nombre debe empezar con "use" (useMyHook)
- Solo puede ser llamado desde componentes React u otros hooks
- Debe ser llamado en el nivel superior del componente
Ejemplo: useFormInput - Custom Hook para formularios
function useFormInput(initialValue = '') {
const [value, setValue] = useState(initialValue);
return {
value,
bind: {
value,
onChange: e => setValue(e.target.value)
},
reset: () => setValue(initialValue)
};
}
// Uso
function LoginForm() {
const email = useFormInput('');
const password = useFormInput('');
const handleSubmit = (e) => {
e.preventDefault();
console.log(email.value, password.value);
};
return (
<form onSubmit={handleSubmit}>
<input {...email.bind} type="email" />
<input {...password.bind} type="password" />
<button type="submit">Login</button>
<button type="button" onClick={password.reset}>Resetear</button>
</form>
);
}
Ejemplo: useFetch - Custom Hook para peticiones HTTP
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
let isMounted = true;
fetch(url)
.then(res => res.json())
.then(data => {
if (isMounted) {
setData(data);
setLoading(false);
}
})
.catch(err => {
if (isMounted) {
setError(err);
setLoading(false);
}
});
return () => { isMounted = false; };
}, [url]);
return { data, loading, error };
}
// Uso
function UserList() {
const { data: users, loading, error } = useFetch('/api/users');
if (loading) return <p>Cargando...</p>;
if (error) return <p>Error</p>;
return (
<ul>
{users.map(user => <li key={user.id}>{user.name}</li>)}
</ul>
);
}
Mejores prácticas con Hooks
✅ Haz esto
- Llama hooks en el nivel superior del componente
- Usa dependency arrays correctamente en useEffect
- Extrae lógica en custom hooks para reutilización
- Usa useCallback y useMemo solo cuando sea necesario
- Mantén hooks simples y enfocados en una tarea
❌ Evita esto
- Llamar hooks dentro de condicionales o loops
- Omitir dependencias en dependency arrays
- Crear hooks sin el prefijo "use"
- Sobreoptimizar con useMemo y useCallback
- Usar hooks en componentes de clase
Conclusión: Domina React Hooks y Escribe Código Mejor
Los React Hooks son el presente y futuro de React. Dominarlos te convertirá en un desarrollador React más efectivo, permitiéndote escribir código más limpio, modular y fácil de mantener. La clave es practicar y comprender los conceptos fundamentales: useState para estado, useEffect para efectos, y crear custom hooks para lógica reutilizable.
Comienza ahora mismo a refactorizar tus componentes de clase a hooks y verás la diferencia en la calidad de tu código.

Sobre el autor
Andres Saumet
Desarrollador Web & Móvil Full Stack · Colombia
Hay mil desarrolladores que pueden hacer que algo funcione. Yo me obsesiono con hacer que funcione y genere dinero.
Soy Andres Saumet, desarrollador Web y Móvil con foco en rentabilidad. Trabajo con startups, emprendedores y empresas que ya tienen una visión clara y necesitan a alguien que la convierta en un producto digital real — uno que los usuarios quieran usar y que el negocio quiera escalar.
Domino React, Next.js, React Native y Node.js. Pero más allá del stack, entiendo cómo piensan los usuarios, cómo fluye un negocio y qué decisiones técnicas impactan directamente en los ingresos.
Cada línea de código que escribo tiene un propósito: que tu producto web o móvil sea más rápido, más usable y más rentable.
¿Tienes un producto que necesita crecer? Construyámoslo juntos.
