Evolución de la gestión de estado en React: de Props Drilling a Zustand

4 min

Introducción

«¿Cómo se puede gestionar el estado con elegancia?» Esta es una cuestión fundamental que todo desarrollador de React debe afrontar a medida que crece un proyecto. Desde el estado sencillo dentro de un componente hasta el estado global complejo compartido entre componentes, la comunidad de React ha explorado numerosas soluciones. Su evolución también refleja una comprensión cada vez más profunda del desarrollo basado en componentes.

Primera etapa: una época sencilla — useState y Props Drilling

Al principio solo teníamos useState (o this.state en los componentes de clase). Cuando varios componentes necesitaban compartir un estado, la recomendación oficial de React era «elevar el estado» (Lifting State Up). El estado se trasladaba al ancestro común más cercano de esos componentes y después se transmitía, junto con su función de actualización, mediante props.

Cuando la jerarquía de componentes se hacía profunda, este patrón provocaba Props Drilling: algunos componentes intermedios recibían props únicamente para pasarlas a descendientes más profundos, sin utilizarlas ellos mismos. Esto aumentaba el acoplamiento entre componentes y dificultaba la refactorización y el mantenimiento.

Segunda etapa: la respuesta oficial — Context API

Para resolver el props drilling, React proporcionó oficialmente la Context API. Esta permite crear un «contexto», proporcionar (Provide) un valor en la parte superior del árbol de componentes y consumirlo (Consume) directamente desde un componente descendiente a cualquier profundidad, sin transmitirlo manualmente nivel por nivel.

// 1. 创建 Context
const ThemeContext = React.createContext('light');

// 2. 在顶层提供值
<ThemeContext.Provider value="dark">
  <App />
</ThemeContext.Provider>

// 3. 在子组件中消费
const theme = useContext(ThemeContext); // 'dark'

Sin embargo, la Context API también tiene una «trampa»: el rendimiento. Cada vez que cambia el Provider y su value, todos los componentes que consumen ese Context vuelven a renderizarse, incluso si solo les interesa una pequeña parte del objeto value. Por ello, la Context API no resulta adecuada para gestionar estados globales complejos que cambian con frecuencia.

Tercera etapa: la era de la unificación — Redux

Antes de que la Context API madurara, Redux irrumpió en escena y se convirtió rápidamente en el estándar de facto para gestionar el estado de aplicaciones grandes y complejas. Inspirándose en la arquitectura Flux y en la programación funcional, aportó:

  • Una única fuente de verdad (Single Source of Truth): El state de toda la aplicación se almacena en un único store.
  • El State es de solo lectura: La única forma de cambiar el state consiste en hacer dispatch de una action.
  • Las modificaciones se realizan con funciones puras: Un reducer recibe el state anterior y una action, y devuelve el nuevo state.

Gracias a su previsibilidad, sus potentes herramientas de depuración (viaje en el tiempo) y su abundante ecosistema de middleware, Redux resolvió los problemas de gestión de estado en aplicaciones grandes. Pero su defecto era igualmente evidente: una gran cantidad de código repetitivo (Boilerplate). Para implementar una función sencilla, los desarrolladores tenían que escribir Actions, Reducers y Dispatchers, con una carga mental considerable.

Cuarta etapa: el renacimiento — soluciones ligeras y Hooks-First

Con la popularización de React Hooks y la reflexión sobre la complejidad de Redux, la comunidad comenzó a crear una nueva generación de bibliotecas de gestión de estado más ligeras. Todas compartían APIs concisas, modelos mentales sencillos y un uso completo de las capacidades de Hooks.

Zustand es un ejemplo destacado. Proporciona una función create extremadamente sencilla para crear un store y, además:

  • No requiere Provider: El Store existe fuera del árbol de componentes de React y se puede importar desde cualquier lugar.
  • API mínima: Se accede al estado y se actualiza mediante un único Hook.
  • Suscripciones selectivas y mejor rendimiento: Cada componente puede suscribirse únicamente a la parte del state que necesita, evitando el problema de rendimiento de la Context API.
const useStore = create(set => ({
  count: 0,
  inc: () => set(state => ({ count: state.count + 1 })),
}));

function Counter() {
  // 只订阅 count 的变化
  const count = useStore(state => state.count);
  return <h1>{count}</h1>;
}

Conclusión: no hay una solución universal, elige según tus necesidades

La evolución de la gestión de estado en React nos enseña que no existe una «mejor solución» válida para siempre, sino la solución más adecuada para cada situación.

  • useState: Siempre es la primera opción para el estado local de un componente.
  • Context API: Adecuada para datos globales que no cambian con frecuencia, como el tema o la información de autenticación del usuario.
  • Zustand / Jotai: Para la mayoría de las aplicaciones que necesitan estado global del lado del cliente, ofrecen un equilibrio excelente entre rendimiento y experiencia de desarrollo.
  • Redux (Redux Toolkit): Sigue siendo una opción fiable para aplicaciones enormes que requieren normas estrictas de flujo de datos, middleware complejo y potentes funciones de depuración.