Skip to main content

React中常用的狀態管理工具

1. React Context API

特點

  • React 內建的狀態管理工具,無需額外安裝。

  • 適合小型到中型專案,用於跨元件共享狀態(例如主題、用戶資訊)。

  • 簡單易用,但不適合超複雜的狀態管理。

安裝: 無需額外安裝,React 16.3 以上版本已內建 Context API。

使用步驟

  1. 創建 Context:建立一個 Context 物件來儲存狀態。

  2. 提供狀態:使用 Provider 將狀態提供給子元件。

  3. 消費狀態:在需要使用狀態的元件中透過 useContext 獲取狀態。

範例程式碼: 假設我們要實現一個簡單的主題切換功能(明亮/暗黑模式)。

// src/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((prevTheme) => (prevTheme === "light" ? "dark" : "light"));
};

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

// 自訂 Hook 用於消費 Context
export const useTheme = () => useContext(ThemeContext);
// src/App.js
import { ThemeProvider } from "./context/ThemeContext";
import ThemeToggleButton from "./components/ThemeToggleButton";

function App() {
return (
<ThemeProvider>
<div style={{ padding: "20px" }}>
<h1>主題切換範例</h1>
<ThemeToggleButton />
</div>
</ThemeProvider>
);
}

export default App;
// src/components/ThemeToggleButton.js
import { useTheme } from "../context/ThemeContext";

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

return (
<div>
<p>目前主題:{theme}</p>
<button onClick={toggleTheme}>切換主題</button>
</div>
);
}

export default ThemeToggleButton;

說明

  • ThemeContext 用來儲存主題狀態和切換函數。

  • ThemeProvider 負責提供狀態給所有子元件。

  • useTheme 是一個自訂 Hook,方便在任何元件中獲取主題狀態。

  • 點擊按鈕會切換 theme 狀態,進而改變應用程式的顯示。

優點

  • 內建於 React,無需額外依賴。

  • 適合簡單的全局狀態管理。

缺點

  • 大型專案中,當 Context 改變頻繁時,可能導致不必要的重新渲染。

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


2. Redux

特點

  • 業界標準的狀態管理庫,適合中大型專案。

  • 提供單向數據流,狀態集中管理。

  • 有豐富的生態系統(如 Redux Toolkit)簡化配置。

安裝

npm install @reduxjs/toolkit react-redux

使用步驟

  1. 配置 Store:使用 Redux Toolkit 創建 store 和 slice。

  2. 提供 Store:在應用程式根元件中使用 Provider。

  3. 連接到元件:使用 useSelector 和 useDispatch 存取和更新狀態。

範例程式碼: 假設我們要實現一個簡單的計數器。

// src/app/store.js
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "../features/counter/counterSlice";

export const store = configureStore({
reducer: {
counter: counterReducer,
},
});
// src/features/counter/counterSlice.js
import { createSlice } from "@reduxjs/toolkit";

const counterSlice = createSlice({
name: "counter",
initialState: {
value: 0,
},
reducers: {
increment: (state) => {
state.value += 1;
},
decrement: (state) => {
state.value -= 1;
},
},
});

export const { increment, decrement } = counterSlice.actions;
export default counterSlice.reducer;
// src/App.js
import { Provider } from "react-redux";
import { store } from "./app/store";
import Counter from "./components/Counter";

function App() {
return (
<Provider store={store}>
<div style={{ padding: "20px" }}>
<h1>Redux 計數器範例</h1>
<Counter />
</div>
</Provider>
);
}

export default App;
// src/components/Counter.js
import { useSelector, useDispatch } from "react-redux";
import { increment, decrement } from "../features/counter/counterSlice";

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

return (
<div>
<p>計數:{count}</p>
<button onClick={() => dispatch(increment())}>增加</button>
<button onClick={() => dispatch(decrement())}>減少</button>
</div>
);
}

export default Counter;

說明

  • createSlice 簡化了 action 和 reducer 的創建。

  • store 集中管理所有狀態。

  • useSelector 用於讀取狀態,useDispatch 用於觸發 action。

  • 點擊按鈕會更新計數器值,並反映到畫面上。

優點

  • 強大的狀態管理能力,適合複雜應用。

  • Redux Toolkit 減少了樣板程式碼,易於學習。

缺點

  • 學習曲線較陡,配置較複雜。

  • 小型專案可能顯得過於繁重。


3. Zustand

特點

  • 輕量級狀態管理庫,API 簡單直觀。

  • 無需 Provider,直接在元件中使用。

  • 適合中小型專案,效能優異。

安裝

npm install zustand

使用步驟

  1. 創建 Store:使用 create 定義狀態和更新函數。

  2. 使用 Store:在元件中直接調用 store 的 Hook。

範例程式碼: 實現一個簡單的計數器。

// src/store/useCounterStore.js
import { create } from "zustand";

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

export default useCounterStore;
// src/App.js
import Counter from "./components/Counter";

function App() {
return (
<div style={{ padding: "20px" }}>
<h1>Zustand 計數器範例</h1>
<Counter />
</div>
);
}

export default App;
// src/components/Counter.js
import useCounterStore from "../store/useCounterStore";

function Counter() {
const { count, increment, decrement } = useCounterStore();

return (
<div>
<p>計數:{count}</p>
<button onClick={increment}>增加</button>
<button onClick={decrement}>減少</button>
</div>
);
}

export default Counter;

說明

  • create 創建了一個 store,包含狀態和更新函數。

  • useCounterStore 是一個 Hook,直接在元件中存取狀態和方法。

  • 不需要額外的 Provider,簡化了配置。

優點

  • API 簡單,學習曲線低。

  • 輕量且高效,適合快速開發。

缺點

  • 不如 Redux 適合超大型專案。

  • 生態系統相對較小。


4. Recoil

特點

  • 由 Facebook 開發,專為 React 設計。

  • 使用原子化的狀態管理(atoms 和 selectors),靈活且直觀。

  • 適合中大型專案,與 React 的整合度高。

安裝

npm install recoil

使用步驟

  1. 創建 Atom:定義狀態的基本單位。

  2. 提供 RecoilRoot:在應用程式根元件中包裹 RecoilRoot。

  3. 使用狀態:透過 useRecoilState 或 useRecoilValue 存取狀態。

範例程式碼: 實現一個簡單的計數器。

// src/atoms/counterAtom.js
import { atom } from "recoil";

export const counterState = atom({
key: "counterState", // 唯一識別
default: 0, // 初始值
});
// src/App.js
import { RecoilRoot } from "recoil";
import Counter from "./components/Counter";

function App() {
return (
<RecoilRoot>
<div style={{ padding: "20px" }}>
<h1>Recoil 計數器範例</h1>
<Counter />
</div>
</RecoilRoot>
);
}

export default App;
// src/components/Counter.js
import { useRecoilState } from "recoil";
import { counterState } from "../atoms/counterAtom";

function Counter() {
const [count, setCount] = useRecoilState(counterState);

return (
<div>
<p>計數:{count}</p>
<button onClick={() => setCount(count + 1)}>增加</button>
<button onClick={() => setCount(count - 1)}>減少</button>
</div>
);
}

export default Counter;

說明

  • atom 定義了一個狀態單位 counterState。

  • RecoilRoot 是必須的,提供 Recoil 的上下文。

  • useRecoilState 類似於 useState,用於讀寫狀態。

優點

  • 與 React 高度整合,支援 React 18 的 concurrent 特性。

  • 原子化設計靈活,易於組合。

缺點

  • 相對較新,社區和資源不如 Redux 豐富。

  • 配置稍顯複雜。


5. MobX

特點

  • 基於響應式程式設計,狀態變化自動觸發更新。

  • 語法直觀,適合快速開發。

  • 適合中小型專案,但也能處理大型應用。

安裝

npm install mobx mobx-react

使用步驟

  1. 創建 Store:使用 makeAutoObservable 定義響應式狀態。

  2. 連接到元件:使用 observer 包裝元件以響應狀態變化。

範例程式碼: 實現一個簡單的計數器。

// src/stores/CounterStore.js
import { makeAutoObservable } from "mobx";

class CounterStore {
count = 0;

constructor() {
makeAutoObservable(this);
}

increment() {
this.count += 1;
}

decrement() {
this.count -= 1;
}
}

export default new CounterStore();
// src/App.js
import Counter from "./components/Counter";

function App() {
return (
<div style={{ padding: "20px" }}>
<h1>MobX 計數器範例</h1>
<Counter />
</div>
);
}

export default App;
// src/components/Counter.js
import { observer } from "mobx-react";
import counterStore from "../stores/CounterStore";

const Counter = observer(() => {
return (
<div>
<p>計數:{counterStore.count}</p>
<button onClick={() => counterStore.increment()}>增加</button>
<button onClick={() => counterStore.decrement()}>減少</button>
</div>
);
});

export default Counter;

說明

  • makeAutoObservable 自動將 store 的屬性和方法變為響應式。

  • observer 包裝元件,確保狀態變化時元件自動重新渲染。

  • 不需要 Provider,配置簡單。

優點

  • 語法簡單,開發效率高。

  • 響應式設計減少了手動更新邏輯。

缺點

  • 狀態管理不如 Redux 結構化,複雜專案可能難以維護。

  • 學習響應式程式設計需要一些時間。


比較與選擇建議

工具適合場景優點缺點
Context API小型專案、全局簡單狀態內建、簡單不適合複雜狀態、效能問題
Redux中大型專案、需要嚴格狀態管理結構化、強大生態學習曲線陡、配置複雜
Zustand中小型專案、快速開發輕量、API 簡單生態較小
Recoil中大型專案、React 深度整合靈活、支援新特性相對新、資源較少
MobX快速開發、響應式設計直觀、高效不夠結構化

選擇建議

  • 如果你是初學者或專案規模小,建議從 Context APIZustand 開始,因為它們簡單且容易上手。

  • 如果專案需要嚴格的狀態管理(如企業級應用),選擇 Redux(建議搭配 Redux Toolkit)。

  • 如果你喜歡響應式設計且希望快速開發,MobX 是很好的選擇。

  • 如果你使用 React 18 並希望更好的整合,Recoil 是一個現代化的選擇。