文章

useReducer Hook 介紹

useReducer Hook 介紹

useReducer 是 React 中的一個 Hook,用來在函數組件中管理更為複雜的狀態邏輯。相比 useStateuseReducer 更適合處理多層次且有邏輯分支的狀態更新,特別是在多個子狀態需要基於不同動作進行更新的情況下。


1. useReducer 的基本概念

useReducer 的工作原理與 Redux 中的 Reducer 相似,它接收一個 reducer 函數和初始狀態,返回當前狀態以及一個 dispatch 函數。當我們調用 dispatch 函數時,會根據指定的 action 來調用 reducer,進而更新狀態。

  • Reducer 是一個純函數,它根據當前的狀態和傳入的 action 來決定並返回新的狀態。
  • Action 是一個帶有類型(type)和可選數據(payload)的對象,用來描述狀態變更的具體操作。

2. useReducer 的語法

1
const [state, dispatch] = useReducer(reducer, initialState);
  • state:當前的狀態值。
  • dispatch:一個函數,調用時傳入一個 action 對象,觸發 reducer 函數更新狀態。
  • reducer:一個純函數 (state, action) => newState,負責根據 action 決定如何更新狀態。
  • initialState:初始狀態。

3. 基本範例

以下是一個使用 useReducer 來實現計數器的範例:

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
33
import React, { useReducer } from 'react';

// 定義 reducer 函數
function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    case 'reset':
      return { count: 0 };
    default:
      throw new Error();
  }
}

function Counter() {
  const initialState = { count: 0 };

  // 使用 useReducer
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>增加</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>減少</button>
      <button onClick={() => dispatch({ type: 'reset' })}>重置</button>
    </div>
  );
}

export default Counter;

解釋:

  • 我們創建了一個 reducer 函數,它接收當前狀態 stateaction,根據不同的 action.type 返回新的狀態。
  • 使用 useReducer 來管理計數器的狀態,初始狀態設為 { count: 0 }
  • 點擊按鈕時,通過 dispatch 傳遞不同的 action 來觸發狀態更新。

4. useReducer 的優勢

  • 更好的狀態管理:當狀態變更邏輯複雜時,useReducer 可以將邏輯集中在一個 reducer 函數中,代碼更清晰、易於維護。
  • 避免多次調用 setState:使用 useState 處理多個相關狀態時,會有多次 setState 調用,而 useReducer 可以將這些邏輯整合為一個狀態更新步驟。
  • 提高可測試性reducer 函數是一個純函數,更容易進行單元測試,因為它不依賴於外部變量或副作用。

5. 複雜範例:表單數據管理

假設我們有一個包含多個輸入字段的表單,我們可以使用 useReducer 來管理表單的狀態。

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import React, { useReducer } from 'react';

// 定義初始狀態
const initialState = {
  username: '',
  email: '',
  password: ''
};

// 定義 reducer 函數
function reducer(state, action) {
  switch (action.type) {
    case 'setField':
      return {
        ...state,
        [action.field]: action.value
      };
    case 'reset':
      return initialState;
    default:
      throw new Error();
  }
}

function SignupForm() {
  const [state, dispatch] = useReducer(reducer, initialState);

  const handleChange = (e) => {
    dispatch({
      type: 'setField',
      field: e.target.name,
      value: e.target.value
    });
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log('提交表單: ', state);
    dispatch({ type: 'reset' });
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        使用者名稱:
        <input
          name="username"
          value={state.username}
          onChange={handleChange}
        />
      </label>
      <br />
      <label>
        電子郵件:
        <input name="email" value={state.email} onChange={handleChange} />
      </label>
      <br />
      <label>
        密碼:
        <input
          type="password"
          name="password"
          value={state.password}
          onChange={handleChange}
        />
      </label>
      <br />
      <button type="submit">註冊</button>
    </form>
  );
}

export default SignupForm;

解釋:

  • 我們將表單的每個字段的狀態整合在一個 state 對象中,並使用 reducer 函數來處理不同的字段變更。
  • 每當用戶輸入數據時,會觸發 dispatch,根據字段名稱和值更新狀態。
  • 提交表單後,表單狀態會重置為初始狀態。

6. useReduceruseState 的比較

特點useStateuseReducer
適用場景簡單狀態變更和邏輯複雜狀態邏輯,多個狀態基於不同的操作進行更新
狀態更新方式直接調用 setState通過 dispatch 發送 action 觸發狀態更新
狀態更新邏輯單純更新狀態,使用較少邏輯使用 reducer 將邏輯和狀態更新分離
可擴展性對於多狀態較難擴展更易於擴展和管理複雜的多狀態更新
  • 如果你的狀態變化相對簡單,可以直接使用 useState
  • 如果你的狀態變化涉及到多個子狀態或者多種操作(例如有不同的行為需要觸發不同的狀態變更),useReducer 會是一個更合適的選擇。

7. 總結

  • useReducer 是管理複雜狀態邏輯的一個強大工具,它適合多層次狀態變化或有明確行為類型的應用場景。
  • 通過 reducer 函數將狀態邏輯與組件分離,提升了代碼的可維護性和可測試性。
  • useReducer 也能和 useContext 結合,來實現全局狀態管理,類似於 Redux 的功能。

在 React 應用中,根據具體的狀態管理需求,可以靈活選擇 useStateuseReducer 來管理狀態。

本文章以 CC BY 4.0 授權