Publicado el 22 de diciembre de 2024
El manejo del estado en aplicaciones React puede volverse complejo rápidamente, especialmente cuando:
El prop drilling ocurre cuando pasamos propiedades a través de múltiples niveles de componentes que no necesitan esos datos, solo para llegar a un componente hijo profundamente anidado.
// Ejemplo de Prop Drilling
function GrandParent({ user }) {
return <Parent user={user} />;
}
function Parent({ user }) {
return <Child user={user} />;
}
function Child({ user }) {
return <GrandChild user={user} />;
}
function GrandChild({ user }) {
return <div>{user.name}</div>;
}Cuando el mismo dato se almacena en múltiples lugares, puede llevar a inconsistencias:
function UserProfile() {
const [user, setUser] = useState({
name: 'Juan',
preferences: { theme: 'dark' }
});
}
function Settings() {
// Duplicación de estado - ¡Peligro!
const [userPreferences, setUserPreferences] = useState({
theme: 'dark'
});
}Para problemas de prop drilling moderados:
const UserContext = React.createContext();
function UserProvider({ children }) {
const [user, setUser] = useState(null);
const value = {
user,
setUser,
};
return (
<UserContext.Provider value={value}>
{children}
</UserContext.Provider>
);
}
// Uso en componentes
function DeepChild() {
const { user } = useContext(UserContext);
return <div>{user.name}</div>;
}Para aplicaciones más complejas, considera usar gestores de estado como Redux o Zustand:
// Ejemplo con Zustand
import create from 'zustand';
const useStore = create((set) => ({
user: null,
setUser: (user) => set({ user }),
clearUser: () => set({ user: null }),
updatePreferences: (preferences) =>
set((state) => ({
user: {
...state.user,
preferences,
},
})),
}));Evita el prop drilling mediante la composición:
function UserData({ children }) {
const [user, setUser] = useState(null);
return children({ user, setUser });
}
// Uso
<UserData>
{({ user, setUser }) => (
<div>
<h1>{user.name}</h1>
<button onClick={() => setUser(null)}>Logout</button>
</div>
)}
</UserData>Centraliza el Estado: Mantén el estado lo más cerca posible de donde se usa.
Divide el Estado: Separa el estado global del local:
// Estado Local const [isOpen, setIsOpen] = useState(false); // Estado Global (Zustand/Redux/Context) const user = useStore(state => state.user);
Optimiza Renders: Usa memoización cuando sea necesario:
const MemoizedChild = React.memo(function Child({ user }) {
return <div>{user.name}</div>;
});Documenta las Decisiones: Mantén un registro de por qué elegiste ciertas soluciones:
/** * UserProvider: Maneja el estado global del usuario * * Usamos Context en lugar de Redux porque: * 1. La aplicación es pequeña/mediana * 2. Las actualizaciones son poco frecuentes * 3. No necesitamos las herramientas de desarrollo de Redux */
El manejo del estado es un desafío fundamental en React. La clave está en:
Con estas estrategias, puedes mantener tu aplicación React mantenible y escalable a largo plazo.