Gestion de Estado
Context API, Redux y Zustand para el estado global
Gestion de Estado Global
Cuando multiples componentes necesitan compartir estado, necesitas una solucion de gestion de estado global. Hay varias opciones segun la complejidad de tu aplicacion.
Context API
import { createContext, useContext, useState } from 'react';
// Crear contexto
const AuthContext = createContext();
// Proveedor
export function AuthProvider({ children }) {
const [usuario, setUsuario] = useState(null);
const login = (datosUsuario) => setUsuario(datosUsuario);
const logout = () => setUsuario(null);
return (
<AuthContext.Provider value={{ usuario, login, logout }}>
{children}
</AuthContext.Provider>
);
}
// Hook personalizado para usar el contexto
export function useAuth() {
const context = useContext(AuthContext);
if (!context) {
throw new Error('useAuth debe usarse dentro de AuthProvider');
}
return context;
}
// Uso
function BarraNav() {
const { usuario, logout } = useAuth();
return (
<nav>
{usuario ? (
<>
<span>Hola, {usuario.nombre}</span>
<button onClick={logout}>Salir</button>
</>
) : (
<Link to="/login">Iniciar sesion</Link>
)}
</nav>
);
}
Zustand (Recomendado)
// npm install zustand
import { create } from 'zustand';
// Crear store
const useStore = create((set) => ({
cuenta: 0,
incrementar: () => set((state) => ({ cuenta: state.cuenta + 1 })),
decrementar: () => set((state) => ({ cuenta: state.cuenta - 1 })),
reiniciar: () => set({ cuenta: 0 })
}));
// Uso en componentes
function Contador() {
const { cuenta, incrementar, decrementar, reiniciar } = useStore();
return (
<div>
<p>Cuenta: {cuenta}</p>
<button onClick={incrementar}>+</button>
<button onClick={decrementar}>-</button>
<button onClick={reiniciar}>Reiniciar</button>
</div>
);
}
// Seleccionar estado especifico (evita re-renders innecesarios)
function MostrarCuenta() {
const cuenta = useStore((state) => state.cuenta);
return <span>{cuenta}</span>;
}
Zustand con Acciones Asincronas
const useTareasStore = create((set, get) => ({
tareas: [],
cargando: false,
error: null,
obtenerTareas: async () => {
set({ cargando: true, error: null });
try {
const respuesta = await fetch('/api/tareas');
const tareas = await respuesta.json();
set({ tareas, cargando: false });
} catch (error) {
set({ error: error.message, cargando: false });
}
},
agregarTarea: async (titulo) => {
const respuesta = await fetch('/api/tareas', {
method: 'POST',
body: JSON.stringify({ titulo })
});
const nuevaTarea = await respuesta.json();
set((state) => ({ tareas: [...state.tareas, nuevaTarea] }));
},
eliminarTarea: (id) => {
set((state) => ({
tareas: state.tareas.filter(t => t.id !== id)
}));
}
}));
Cuando Usar Cada Opcion
| Solucion | Usar cuando |
|---|---|
| Props | Estado local entre padre e hijo |
| Context | Estado simple compartido (tema, auth) |
| Zustand | Estado complejo, rendimiento importa |
| Redux | Apps muy grandes, necesidad de middleware |
Mejores Practicas
- Empieza simple: Usa estado local primero
- No sobreuses estado global: Solo para datos realmente compartidos
- Divide stores: Un store por dominio (auth, carrito, etc.)