Lo que Aprenderás en Este Tutorial
✓ useState - Fundamentos de gestión de estado
✓ useEffect - Manejo de efectos secundarios
✓ useContext - Compartir estado global
✓ useReducer - Gestión de estado complejo
✓ useMemo/useCallback - Optimización de rendimiento
✓ Custom Hooks - Reutilización de lógica
Prerrequisitos
- Conocimiento básico de JavaScript
- Entendimiento básico de React (componentes, props)
- Node.js instalado
Configuración del Proyecto
# Crear proyecto
npx create-react-app hooks-tutorial
cd hooks-tutorial
# Iniciar servidor de desarrollo
npm start
Paso 1: useState - Fundamentos de Gestión de Estado
Uso Básico
// src/components/Counter.jsx
import { useState } from 'react';
export default function Counter() {
// [valor del estado, función de actualización] = useState(valor inicial)
const [count, setCount] = useState(0);
return (
<div>
<p>Contador: {count}</p>
<button onClick={() => setCount(count + 1)}>
Incrementar
</button>
<button onClick={() => setCount(count - 1)}>
Decrementar
</button>
<button onClick={() => setCount(0)}>
Resetear
</button>
</div>
);
}
Gestión de Estado de Objeto
// src/components/UserForm.jsx
import { useState } from 'react';
export default function UserForm() {
const [user, setUser] = useState({
nombre: '',
email: '',
edad: ''
});
const handleChange = (e) => {
const { name, value } = e.target;
// Usa spread operator para preservar valores existentes
setUser(prev => ({
...prev,
[name]: value
}));
};
return (
<form>
<input
name="nombre"
value={user.nombre}
onChange={handleChange}
placeholder="Nombre"
/>
<input
name="email"
value={user.email}
onChange={handleChange}
placeholder="Email"
/>
<input
name="edad"
type="number"
value={user.edad}
onChange={handleChange}
placeholder="Edad"
/>
<pre>{JSON.stringify(user, null, 2)}</pre>
</form>
);
}
Paso 2: useEffect - Manejo de Efectos Secundarios
useEffect Básico
// src/components/Timer.jsx
import { useState, useEffect } from 'react';
export default function Timer() {
const [seconds, setSeconds] = useState(0);
const [isRunning, setIsRunning] = useState(false);
useEffect(() => {
let interval = null;
if (isRunning) {
interval = setInterval(() => {
setSeconds(prev => prev + 1);
}, 1000);
}
// Función de limpieza
return () => {
if (interval) clearInterval(interval);
};
}, [isRunning]); // Se ejecuta cuando isRunning cambia
return (
<div>
<p>Tiempo transcurrido: {seconds} segundos</p>
<button onClick={() => setIsRunning(!isRunning)}>
{isRunning ? 'Detener' : 'Iniciar'}
</button>
<button onClick={() => setSeconds(0)}>Resetear</button>
</div>
);
}
Obtención de Datos
// src/components/UserList.jsx
import { useState, useEffect } from 'react';
export default function UserList() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchUsers = async () => {
try {
setLoading(true);
const response = await fetch(
'https://jsonplaceholder.typicode.com/users'
);
if (!response.ok) throw new Error('Error al obtener datos');
const data = await response.json();
setUsers(data);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
fetchUsers();
}, []); // Array vacío = solo se ejecuta al montar
if (loading) return <p>Cargando...</p>;
if (error) return <p>Error: {error}</p>;
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name} ({user.email})</li>
))}
</ul>
);
}
Paso 3: useContext - Compartir Estado Global
Creando y Usando Context
// src/context/ThemeContext.jsx
import { createContext, useContext, useState } from 'react';
const ThemeContext = createContext();
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme(prev => prev === 'light' ? 'dark' : 'light');
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
export function useTheme() {
const context = useContext(ThemeContext);
if (!context) {
throw new Error('useTheme debe usarse dentro de ThemeProvider');
}
return context;
}
Paso 4: Custom Hooks - Reutilización de Lógica
useLocalStorage
// src/hooks/useLocalStorage.js
import { useState, useEffect } from 'react';
export function useLocalStorage(key, initialValue) {
const [value, setValue] = useState(() => {
try {
const item = localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch {
return initialValue;
}
});
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue];
}
useFetch
// src/hooks/useFetch.js
import { useState, useEffect } from 'react';
export function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const abortController = new AbortController();
const fetchData = async () => {
try {
setLoading(true);
const response = await fetch(url, {
signal: abortController.signal
});
if (!response.ok) throw new Error('Error de red');
const json = await response.json();
setData(json);
setError(null);
} catch (err) {
if (err.name !== 'AbortError') {
setError(err.message);
}
} finally {
setLoading(false);
}
};
fetchData();
return () => abortController.abort();
}, [url]);
return { data, loading, error };
}
Mejores Prácticas
1. Consejos de useState
- Mantén el estado mínimo
- Deriva valores mediante computación, no useState
- Usa spread operator al actualizar objetos
2. Consejos de useEffect
- Configura arrays de dependencias correctamente
- No olvides funciones de limpieza
- Cuidado con los bucles infinitos
3. Optimización de Rendimiento
- Evita optimización excesiva
- Mide antes de optimizar
- Usa memo, useMemo, useCallback solo donde sea necesario
4. Custom Hooks
- Usa para reutilización de lógica
- Los nombres deben empezar con "use"
- Sigue el principio de responsabilidad única
Resumen
React Hooks permiten que los componentes funcionales manejen estado y efectos secundarios. Después de dominar los básicos useState y useEffect, avanza a gestión de estado complejo con useContext y useReducer, y optimiza el rendimiento con useMemo y useCallback.
← Volver a la lista