Ta sử dụng hook useReducer khi cần quản lý những state phức tạp.

Usage

Giả sử ta có một đoạn code React sử dụng useState đơn giản như sau:

import { useState } from "react"
 
function App(props) {
  const [count, setCount] = useState(0)
 
  function increment() {
    setCount((prevCount) => prevCount + 1)
  }
 
  function decrement() {
    setCount((prevCount) => prevCount - 1)
  }
 
  return (
    <div>
      <button onClick={decrement}>-</button>
      <p>{count}</p>
      <button onClick={increment}>+</button>
    </div>
  )
}

Để thay thế useState bằng useReducer, trước tiên ta cần import và gọi sử dụng như sau:

import { useReducer } from "react"
 
function App(props) {
  const [] = useReducer()
 
  // ...
}

Hook useReducer nhận vào một hàm reducer và một state khởi tạo. Kèm theo đó, giá trị trả về của hook là state và một hàm dispatch:

import { useReducer } from "react"
 
function reducer() {}
 
function App(props) {
  const [state, dispatch] = useReducer(reducer, { count: 0 })
 
  // ...
}

Tham số của reducer là state và action. Giá trị trả về của nó là state mới:

import { useReducer } from "react"
 
function reducer(state, action) {
  return { count: state.count + 1 }
}
 
function App(props) {
  const [state, dispatch] = useReducer(reducer, { count: 0 })
 
  // ...
}

Khi một sự kiện xảy ra, ta cần gọi hàm dispatch để thay đổi state. Trong trường hợp này, reducer chỉ xử lý trường hợp tăng giá trị của biến count nên ta chỉ gọi dispatch ở trong hàm increment:

import { useReducer } from "react"
 
function reducer(state, action) {
  return { count: state.count + 1 }
}
 
function App(props) {
  const [state, dispatch] = useReducer(reducer, { count: 0 })
 
  function increment() {
    dispatch()
  }
 
  function decrement() {}
 
  return (
    <div>
      <button onClick={decrement}>-</button>
      <p>{state.count}</p>
      <button onClick={increment}>+</button>
    </div>
  )
}
 
export default App

Để xử lý thêm trường hợp giảm giá trị của biến count, ta cần truyền vào dispatch một action cho biết là ta muốn thực hiện hành động nào. Cấu trúc của action này là do tự ta quy ước.

import { useReducer } from "react"
 
const ACTION = {
  INCREMENT: "increment",
  DECREMENT: "decrement",
}
 
function reducer(state, action) {
  switch (action.type) {
    case ACTION.INCREMENT:
      return { count: state.count + 1 }
    case ACTION.DECREMENT:
      return { count: state.count - 1 }
    default:
      return state
  }
}
 
function App(props) {
  const [state, dispatch] = useReducer(reducer, { count: 0 })
 
  function increment() {
    dispatch({ type: ACTION.INCREMENT })
  }
 
  function decrement() {
    dispatch({ type: ACTION.DECREMENT })
  }
 
  return (
    <div className="App">
      <button onClick={decrement}>-</button>
      <span>{state.count}</span>
      <button onClick={increment}>+</button>
    </div>
  )
}
 
export default App

Hàm reducer sẽ thực hiện thay đổi state dựa trên action truyền vào. Bằng cách này, ta sẽ có thể kiểm soát được kết quả của việc cập nhật state.

Resources