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;
說明:
-
建立 ThemeContext 並用 Provider 包裝應用程式。
-
使用 useContext 消費 Context,取得 theme 和 toggleTheme。
-
點擊按鈕切換主題,更新 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;
說明:
-
建立 Redux Store 和 Reducer,定義狀態更新邏輯。
-
使用 Provider 將 Store 注入應用程式。
-
使用 useSelector 取得狀態,useDispatch 發送 action 更新狀態。
-
點擊按鈕會觸發 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;
說明:
-
使用 create 建立 Zustand Store,定義狀態和更新函數。
-
在元件中直接使用 useStore 取得狀態和方法,無需 Provider。
-
點擊按鈕呼叫 increment 或 decrement,Zustand 自動更新狀態並只重新渲染相關元件。
比較總結
| 特性 | React Context | Redux | Zustand |
|---|---|---|---|
| 依賴 | 內建於 React,無需額外安裝 | 需安裝 redux 和 react-redux | 需安裝 zustand(輕量級) |
| 學習曲線 | 簡單 | 較陡,需要理解 Action/Reducer | 簡單,類似 Hook 風格 |
| 樣板程式碼 | 少 | 多 | 極少 |
| 效能 | 頻繁更新可能導致過多渲染 | 高效,但需手動優化 | 高效,自動避免不必要渲染 |
| 除錯工具 | 無內建工具 | Redux DevTools 強大 | 支援簡單除錯中間件 |
| 適合場景 | 小型專案、簡單全局狀態 | 大型專案、複雜狀態邏輯 | 中小型專案、靈活狀態管理 |
| 非同步支援 | 需自行處理 | 透過中間件(如 redux-thunk) | 內建支援,無需中間件 |
如何選擇?
-
React Context:
-
如果你的專案規模小,狀態簡單(例如主題、語言設定),使用 React Context 就足夠。它簡單易用,無需額外依賴。
-
但如果狀態更新頻繁或邏輯複雜,建議考慮其他工具。
-
-
Redux:
-
如果你正在開發大型應用程式,需要嚴格的資料流控制、強大的除錯工具,或有複雜的非同步邏輯,Redux 是最佳選擇。
-
但要注意樣板程式碼較多,可能增加開發時間。
-
-
Zustand:
-
如果你想要一個輕量、靈活且易於上手的解決方案,Zustand 是很好的選擇。它適合中小型專案,特別是希望減少樣板程式碼的場景。
-
對於超大型專案,可能需要額外結構化管理。
-