React 状态管理演进史:从 Props Drilling 到 Zustand

6 min

引言

“如何优雅地管理状态?” 这是每一个 React 开发者在项目成长过程中都必须面对的核心问题。从简单的组件内部状态,到复杂的跨组件全局状态,React 社区探索出了多种解决方案。这些方案的演进,也反映了我们对组件化开发理解的不断深化。

阶段一:朴素的时代 —— useState 与属性钻探 (Props Drilling)

在最开始,我们只有 useState(或类组件的 this.state)。当一个状态需要被多个组件共享时,React 的官方建议是 “状态提升” (Lifting State Up)。我们将状态提升到这些组件的最近公共父组件中,再通过 props 将状态和更新函数传递下去。

当组件层级很深时,这种模式就导致了 “属性钻探” (Props Drilling):一些中间层的组件仅仅是为了将 props 传递给更深层的子组件,自身完全用不到这些 props。这使得组件的耦合度增高,重构和维护变得困难。

阶段二:官方的答案 —— Context API

为了解决“属性钻探”的问题,React 官方提供了 Context API。它允许我们创建一个“上下文”,并在组件树的顶层提供 (Provide) 一个值,然后在任何深度的子组件中都可以直接消费 (Consume) 这个值,无需手动层层传递。

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

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

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

然而,Context API 也有其“陷阱”:性能问题。只要 Providervalue 发生变化,所有消费该 Context 的组件 都会 重新渲染,即使它关心的只是 value 对象中的一小部分。这使得 Context API 不适合管理频繁变化的、复杂的全局状态。

阶段三:大一统时代 —— Redux

在 Context API 尚不成熟的年代,Redux 横空出世,迅速成为大型复杂应用状态管理的事实标准。它借鉴了 Flux 架构和函数式编程思想,带来了:

  • 单一数据源 (Single Source of Truth): 整个应用的 state 被存储在一个单一的 store 中。
  • State 是只读的: 唯一改变 state 的方法就是 dispatch 一个 action。
  • 使用纯函数来执行修改: Reducer 接收先前的 state 和 action,并返回新的 state。

Redux 凭借其可预测性、强大的调试工具(时间旅行)和丰富的中间件生态,解决了大型应用中的状态管理难题。但它的缺点也同样明显:繁琐的样板代码 (Boilerplate)。为了实现一个简单的功能,开发者需要编写 Actions, Reducers, Dispatchers,心智负担较重。

阶段四:文艺复兴 —— 轻量级、Hooks-First 的方案

随着 React Hooks 的普及,以及对 Redux 复杂性的反思,社区开始涌现出一批新的、更轻量的状态管理库。它们的共同特点是 API 简洁、心智模型简单,并且充分利用了 Hooks 的能力。

Zustand 是其中的杰出代表。它提供了一个极其简单的 create 函数来创建 store,并且:

  • 无需 Provider: Store 存在于 React 组件树之外,可以在任何地方导入使用。
  • API 极简: 通过一个 Hook 即可访问和更新状态。
  • 选择性订阅,性能更优: 组件可以只订阅它关心的那一部分 state,避免了 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>;
}

结论:没有银弹,按需选择

React 状态管理的演进史告诉我们,没有一劳永逸的“最佳方案”,只有“最适合当前场景”的方案。

  • useState: 永远是组件局部状态的首选。
  • Context API: 适合管理那些不经常变化的全局数据,如主题、用户认证信息等。
  • Zustand / Jotai: 对于大多数需要客户端全局状态的应用来说,它们在性能和开发体验之间取得了绝佳的平衡。
  • Redux (Redux Toolkit): 对于需要严格数据流规范、复杂中间件和强大调试能力的超大型应用,它依然是可靠的选择。