Jeff的隨手筆記

學習當一個前端工程師

0%

『Day 23』結合 Context 與 Reducer

前言

還記得前面幾篇文章中,我們分別介紹了 Context 和 Reducer 這兩個強大的功能。當時不知道大家是否也和我有一樣的想法:「這兩個功能都這麼好用,那…能不能一起使用呢?」

其實 React 早就想到這個問題了!透過 Context 和 Reducer 的結合,我們可以建立一個更完整的狀態管理方案。今天就讓我來分享這個超強組合的使用心得。

Context + Reducer:完美搭檔

想像一下,如果我們的應用程式是一間公司:Context 就像是公司的通訊系統,讓各部門都能接收到重要訊息;而 Reducer 則像是公司的標準作業流程,確保所有的狀態更新都按照規定執行。當這兩者結合在一起,就能建立一個有效率且井然有序的管理系統。

讓我們來看看如何實作這個組合:

1. 建立 Context 容器

首先,我們需要建立兩個 Context:一個用於存放資料,另一個用於發送更新指令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// TasksContext.js
const TasksContext = createContext(null);
const TasksDispatchContext = createContext(null);

function TasksProvider({ children }) {
const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);

return (
<TasksContext.Provider value={tasks}>
<TasksDispatchContext.Provider value={dispatch}>
{children}
</TasksDispatchContext.Provider>
</TasksContext.Provider>
);
}

2. 建立自訂 Hook

為了讓使用更方便,我們可以建立自訂的 Hook:

1
2
3
4
5
6
7
function useTasks() {
return useContext(TasksContext);
}

function useTasksDispatch() {
return useContext(TasksDispatchContext);
}

3. 實際運用

在應用程式中使用這個組合:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 在根元件中包裹整個應用
function App() {
return (
<TasksProvider>
<TaskList />
</TasksProvider>
);
}

// 在任何子元件中使用
function TaskList() {
const tasks = useTasks();
const dispatch = useTasksDispatch();

return (
<div>
{tasks.map(task => (
<Task
key={task.id}
task={task}
onDelete={() => {
dispatch({
type: 'deleted',
id: task.id
});
}}
/>
))}
</div>
);
}

這個組合帶來的好處

透過 Context 和 Reducer 的結合,我們獲得了許多優勢:

  1. 程式碼更好維護:所有的狀態邏輯都集中在一個地方
  2. 避免 props 層層傳遞:不再需要透過中間元件傳遞狀態
  3. 狀態更新更有條理:所有的更新都經過 Reducer 的統一管理
  4. 元件職責更單純:元件可以專注在畫面呈現上

使用時機與建議

這個組合特別適合:

  • 中型以上的專案
  • 需要跨多層級共享狀態的情況
  • 狀態更新邏輯相對複雜的場景

一些實用的小技巧:

  1. 把相關的程式碼放在同一個檔案
  2. 善用自訂 Hook 簡化使用方式
  3. 適時添加錯誤提示(例如:當 Hook 在 Provider 外使用時)

總結

Context 和 Reducer 的結合不只解決了狀態管理的問題,更帶來了程式碼組織和維護上的便利。雖然對於小型專案來說可能有點過度設計,但當專案開始成長時,這個組合絕對是個值得考慮的選擇。