Skip to main content

React中常用的狀態管理工具:React context vs. redux vs. zustand

1. React Context

React Context 是 React 內建的狀態管理工具,用來在元件樹中共享資料,無需通過 props 一層層傳遞。它適合用於輕量級的狀態管理,特別是全局但不常變動的資料。

特點

  • 內建於 React:無需額外安裝,直接使用 React.createContext。

  • 簡單易用:適合小型到中型應用程式,或共享簡單的全局狀態(如主題、用戶資料)。

  • 更新機制:當 Context 的值改變時,消費該 Context 的元件會重新渲染。

  • 限制:不適合複雜的狀態邏輯或頻繁更新的狀態,因為可能導致不必要的重新渲染。

優點

  • 無需額外依賴,減少專案體積。

  • 設定簡單,適合初學者或小型專案。

  • 與 React 生態系高度整合,API 直觀。

缺點

  • 當狀態頻繁更新時,可能導致效能問題,因為所有消費 Context 的元件都會重新渲染。

  • 缺乏內建的中間件或除錯工具,難以追蹤複雜狀態變化。

  • 不適合管理複雜的狀態邏輯。

使用情境

  • 共享全局但不常變動的資料,例如:

    • 主題切換(明暗模式)。

    • 使用者認證資訊(已登入用戶資料)。

    • 語言設定(i18n)。

  • 小型應用程式,無需複雜的狀態管理。

程式碼範例

以下是一個使用 React Context 管理主題的簡單範例:

// ThemeContext.js
import { createContext, useContext, useState } from "react";

// 建立 Context
const ThemeContext = createContext();

// Provider 元件
export const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState("light");

const toggleTheme = () => {
setTheme(theme === "light" ? "dark" : "light");
};

return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
};

// 自訂 Hook 用於消費 Context
export const useTheme = () => useContext(ThemeContext);

// App.js
import { ThemeProvider, useTheme } from "./ThemeContext";

function App() {
return (
<ThemeProvider>
<MainComponent />
</ThemeProvider>
);
}

function MainComponent() {
const { theme, toggleTheme } = useTheme();

return (
<div
style={{
background: theme === "light" ? "#fff" : "#333",
color: theme === "light" ? "#000" : "#fff",
}}
>
<h1>目前主題:{theme}</h1>
<button onClick={toggleTheme}>切換主題</button>
</div>
);
}

export default App;

說明

  1. 建立 ThemeContext 並用 Provider 包裝應用程式。

  2. 使用 useContext 消費 Context,取得 theme 和 toggleTheme。

  3. 點擊按鈕切換主題,更新 Context 的值,所有消費該 Context 的元件都會重新渲染。


2. Redux

Redux 是一個獨立的狀態管理庫,廣泛用於 React 生態系,適合管理複雜的全局狀態。它遵循單向資料流,並提供強大的工具來追蹤和除錯狀態變化。

特點

  • 集中式狀態管理:所有狀態儲存在單一的 Store 中,元件通過 dispatch action 來更新狀態。

  • 可預測性:狀態變化透過純函數(Reducer)處理,保證一致性。

  • 工具支援:Redux DevTools 提供強大的除錯功能,可追蹤狀態變化歷史。

  • React-Redux:官方提供的 React 綁定庫,簡化 Redux 與 React 的整合。

優點

  • 適合大型應用程式,特別是有複雜狀態邏輯的專案。

  • 強大的除錯工具(Redux DevTools),方便追蹤問題。

  • 中間件支援(如 redux-thunk 或 redux-saga),適合處理非同步邏輯。

  • 生態系成熟,社群資源豐富。

缺點

  • 設定繁瑣,需要撰寫大量樣板程式碼(boilerplate code)。

  • 學習曲線較陡,對於初學者來說可能較難上手。

  • 小型專案可能顯得過於複雜,增加維護成本。

使用情境

  • 大型應用程式,涉及多個元件共享複雜狀態。

  • 需要強大的除錯功能或中間件來處理非同步邏輯。

  • 團隊需要嚴格的資料流控制和可預測性。

程式碼範例

以下是一個使用 Redux 管理計數器的範例:

// store.js
import { createStore } from "redux";

// 初始狀態
const initialState = {
count: 0,
};

// Reducer
const counterReducer = (state = initialState, action) => {
switch (action.type) {
case "INCREMENT":
return { ...state, count: state.count + 1 };
case "DECREMENT":
return { ...state, count: state.count - 1 };
default:
return state;
}
};

// 建立 Store
export const store = createStore(counterReducer);

// App.js
import { Provider, useSelector, useDispatch } from "react-redux";
import { store } from "./store";

function App() {
return (
<Provider store={store}>
<Counter />
</Provider>
);
}

function Counter() {
const count = useSelector((state) => state.count);
const dispatch = useDispatch();

return (
<div>
<h1>計數器:{count}</h1>
<button onClick={() => dispatch({ type: "INCREMENT" })}>加 1</button>
<button onClick={() => dispatch({ type: "DECREMENT" })}>減 1</button>
</div>
);
}

export default App;

說明

  1. 建立 Redux Store 和 Reducer,定義狀態更新邏輯。

  2. 使用 Provider 將 Store 注入應用程式。

  3. 使用 useSelector 取得狀態,useDispatch 發送 action 更新狀態。

  4. 點擊按鈕會觸發 action,Reducer 根據 action type 更新狀態。


3. Zustand

Zustand 是一個輕量級的狀態管理庫,設計簡單且靈活,結合了 Redux 的集中式管理和 Context 的簡潔性。它不需要樣板程式碼,API 直觀,適合中小型專案。

特點

  • 輕量級:檔案大小小(約 1KB),效能優異。

  • 簡單 API:使用 Hook 風格,無需 Provider,直接在元件中呼叫。

  • 靈活:支援同步和非同步狀態更新,無需額外中間件。

  • 可擴展:支援中間件(如持久化、除錯)。

優點

  • 設定簡單,幾乎無樣板程式碼,學習曲線低。

  • 高效能,僅更新消費特定狀態的元件,避免不必要的重新渲染。

  • 支援 TypeScript,開發體驗良好。

  • 適合中小型專案,兼顧靈活性和效能。

缺點

  • 社群和生態系不如 Redux 成熟,資源較少。

  • 對於超大型應用程式,可能需要額外結構化管理。

  • 除錯工具不如 Redux DevTools 強大。

使用情境

  • 中小型應用程式,需簡單的全局狀態管理。

  • 希望減少樣板程式碼,快速開發。

  • 需要靈活處理同步或非同步狀態的場景。

程式碼範例

以下是一個使用 Zustand 管理計數器的範例:

// store.js
import create from "zustand";

export const useStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
}));

// App.js
import { useStore } from "./store";

function App() {
const { count, increment, decrement } = useStore();

return (
<div>
<h1>計數器:{count}</h1>
<button onClick={increment}>加 1</button>
<button onClick={decrement}>減 1</button>
</div>
);
}

export default App;

說明

  1. 使用 create 建立 Zustand Store,定義狀態和更新函數。

  2. 在元件中直接使用 useStore 取得狀態和方法,無需 Provider。

  3. 點擊按鈕呼叫 increment 或 decrement,Zustand 自動更新狀態並只重新渲染相關元件。


比較總結

特性React ContextReduxZustand
依賴內建於 React,無需額外安裝需安裝 redux 和 react-redux需安裝 zustand(輕量級)
學習曲線簡單較陡,需要理解 Action/Reducer簡單,類似 Hook 風格
樣板程式碼極少
效能頻繁更新可能導致過多渲染高效,但需手動優化高效,自動避免不必要渲染
除錯工具無內建工具Redux DevTools 強大支援簡單除錯中間件
適合場景小型專案、簡單全局狀態大型專案、複雜狀態邏輯中小型專案、靈活狀態管理
非同步支援需自行處理透過中間件(如 redux-thunk)內建支援,無需中間件

如何選擇?

  • React Context

    • 如果你的專案規模小,狀態簡單(例如主題、語言設定),使用 React Context 就足夠。它簡單易用,無需額外依賴。

    • 但如果狀態更新頻繁或邏輯複雜,建議考慮其他工具。

  • Redux

    • 如果你正在開發大型應用程式,需要嚴格的資料流控制、強大的除錯工具,或有複雜的非同步邏輯,Redux 是最佳選擇。

    • 但要注意樣板程式碼較多,可能增加開發時間。

  • Zustand

    • 如果你想要一個輕量、靈活且易於上手的解決方案,Zustand 是很好的選擇。它適合中小型專案,特別是希望減少樣板程式碼的場景。

    • 對於超大型專案,可能需要額外結構化管理。