React 狀態管理演進史:從 Props Drilling 到 Zustand

6 分鐘

引言

「如何優雅地管理狀態?」這是每一個 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): 對於需要嚴格資料流規範、複雜中介軟體和強大除錯能力的超大型應用程式,它依然是可靠的選擇。