了解 useReducer React Hook 的用途以及如何使用它!
自從 React 引入了 hooks 以來,我在幾個專案中都使用過它們,它們真的很強大。
移除所有基於 class 的組件,讓代碼更像是真正的 JavaScript。而且函數組件終於可以管理狀態了。
如果你對 hooks 還不熟悉,請先看看我的React hooks介紹。
我有時會使用到的一個 Hook 是 useReducer
。
import React, { useReducer } from 'react'
這個 Hook 用於管理狀態,類似於 useState
,但更複雜。
這就是 useState
和 useReducer
的關鍵差異:使用 useReducer
時,通過傳遞消息來改變狀態,而不是直接調用狀態更新函數。
如果你知道 Redux 是如何工作的,這就基本上是一樣的。一個 reducer 是一個純函數,它根據先前的狀態和已分發的動作計算出下一個狀態。
(currentState, action) => newState
“純函數” 是什麼意思?純函數接收輸入並返回輸出,而不會改變輸入或其他任何東西。這意味著 reducer 返回一個完全替換先前狀態的全新狀態。
一個 reducer 應該:
- 永遠不要改變其參數
- 永遠不要生成副作用(不要有任何改變狀態的 API 調用)
- 永遠不要調用非純函數,即根據與其輸入之外的因素改變其輸出的函數(例如
Date.now()
或Math.random()
)
雖然沒有強制要求,但你應該遵守這些規則。這樣做的好處是:reducer 更容易進行測試,因為它們沒有副作用。
這允許集中管理狀態,允許組件通過發送消息來修改狀態,還可以在組件中使用和更改較為複雜的狀態。
讓我們通過一個計數器組件來舉個例子。
useReducer
接受一個 reducer 函數和一個初始狀態值作為參數。在這個例子中,我們的狀態是一個整數,起始值為 0:
const Counter = () => {
const [state, dispatch] = useReducer(reducer, 0)
}
reducer 是一個函數,如前所述,它接收當前狀態和一個動作作為參數,這個動作可以是你想要的任意類型:
const reducer = (state, action) => {
switch (action) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
throw new Error()
}
}
我們還讓組件輸出一些 JSX 代碼,使這個簡單的應用程序正常運行:
const Counter = () => {
const [count, dispatch] = useReducer(reducer, 0)
return (
<>
Counter: {count}
<button onClick={() => dispatch('INCREMENT')}>+</button>
<button onClick={() => dispatch('DECREMENT')}>-</button>
</>
)
}
以下是在 CodePen 上的完整示例:
React useReducer Hook by Flavio Copes (@flaviocopes) on CodePen
現在,想像一下這個狀態可能是一個擁有很多屬性的對象,而不同的動作僅在一個時間點上改變一個屬性。這是使用此 Hook 的一個很好的案例。