了解 useReducer React Hook 的用途以及如何使用它!

自從 React 引入了 hooks 以來,我在幾個專案中都使用過它們,它們真的很強大。

移除所有基於 class 的組件,讓代碼更像是真正的 JavaScript。而且函數組件終於可以管理狀態了。

如果你對 hooks 還不熟悉,請先看看我的React hooks介紹

我有時會使用到的一個 Hook 是 useReducer

import React, { useReducer } from 'react'

這個 Hook 用於管理狀態,類似於 useState,但更複雜。

這就是 useStateuseReducer 的關鍵差異:使用 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 的一個很好的案例。