iT邦幫忙

2022 iThome 鐵人賽

DAY 22
0
自我挑戰組

我與 React 的 30天系列 第 22

Day 22 useReducer 有比 useState

  • 分享至 

  • xImage
  •  

一連幾天都在介紹 memouseCallbackuseMemo

今天我們就來換個口味來介紹 useReducer,看看他能拿來做什麼?

useReducer 能幹嘛。

一如既往,先來看看官方對於 useReducer 給的定義

An alternative to useState. Accepts a reducer of type (state, action) => newState, and returns the current state paired with a dispatch method.
(If you’re familiar with Redux, you already know how this works.)

useReducer is usually preferable to useState when you have complex state logic that involves multiple sub-values or when the next state depends on the previous one. useReducer also lets you optimize performance for components that trigger deep updates because
you can pass dispatch down instead of callbacks.

文件中提到了,useReducer是可作爲一個useState替代方案,而且可以管理更複雜的邏輯,以及狀態

以我們在使用 useState 的時候,我通常都只會定義一個狀態,若要管理以及定義多個狀態,我們會使用更多的 useState,並且使用一個function 去包裝我們要的邏輯,簡單舉個例子

這邊我們建立兩個數字的狀態,並且做出三個 function,去包裝我們想要達成的邏輯~

// App.js
import { useState } from "react"

const App = () => {
  const [count, setCount] = useState(0)
  const [secondCount, setSecondCount] = useState(10)


  const addHandler = () => {
    setCount(perv => perv + 1)
    setSecondCount(perv => perv + 2)
  }

  const minusHandler = () => {
    setCount(perv => perv - 1)
    setSecondCount(perv => perv - 2)
  }

  const resetHandler = () => {
    setCount(0)
    setSecondCount(10)
  }

  return (
    <div>
      <div>
        第一個數字: {count}
      </div>
      <button onClick={addHandler}>點我 + </button>
      <button onClick={resetHandler}>重置</button>
      <button onClick={minusHandler}>點我 - </button>
      <div>
      第二個數字: {secondCount}
      </div>
    </div>
  )
}

export default App

那接下來我們來看看 useReducer 是怎麼寫的,並且可以達到一樣的效果

// App.js
import { useReducer } from 'react'

const initialState = { count: 0, secondCount: 10 };

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {
        count: state.count + 1, 
        secondCount: state.secondCount + 1,  
      };
    case 'decrement':
      return {
        count: state.count - 1,
        secondCount: state.secondCount - 2,  
      };
    case 'reset':
      return initialState
    default:
      throw new Error();
  }
}

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

  return (
    <div>
      <div>
        第一個數字: {state.count}
      </div>
      <button onClick={() => dispatch({type: 'decrement'})}>點我 + </button>
      <button onClick={() => dispatch({type: 'increment'})}>點我 - </button>
      <button onClick={() => dispatch({type: 'reset'})}>重置</button>
      <div>
        第二個數字: {state.secondCount}
      </div>
    </div>
  );
}

export default App;

一開始看到會覺得很複雜,但是讓我們來一一拆解吧

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

我們先看到 state 以及 initialState

useReducer第二個參數,顧名思義它就是起始的狀態,通常我們會給他一個物件,畢竟我們是要改變以及管理狀態

所以這邊我們定義 initialState 為這樣

const initialState = { count: 0, secondCount: 10 }

然後我們將state在畫面上印出來,會得到下面這樣

有沒有很像我們之前很常使用的 useState,設定一個常數,並且給他初始值

再來就是我們要如何去改變狀態

再來回頭看第useReduce一個參數看起,他會接受一個 function

在這邊我們定義為 reducer function

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {
        count: state.count + 1, 
        secondCount: state.secondCount + 1,  
      };
    case 'decrement':
      return {
        count: state.count - 1,
        secondCount: state.secondCount - 2,  
      };
    case 'reset':
      return initialState
    default:
      throw new Error();
  }
}

先看到這裡 reducer(state, action)

action會被 dispatch 呼叫,而呼叫的條件則是我們定義的,這邊我們將他定義為 typeincrementdecrementreset時,分別會去做什麼事,像是下面我們所呼叫的樣子

<button onClick={() => dispatch({type: 'decrement'})}>點我 - </button>
<button onClick={() => dispatch({type: 'increment'})}>點我 + </button>
<button onClick={() => dispatch({type: 'reset'})}>重置</button>

而這裡的state則是剛剛陣列中的 state

雖然這樣看起來有點複雜,但是如果將 useReducer 用熟之後,你會發現它可以做到 useState做不到的事,明天我們將為介紹 useReducer + useContenxt 的組合技~

小結

今天介紹了 useReducer 起初我看到他時我也是看得一頭霧水,但是只要熟悉之後他就是很強的武器了,明天會繼續介紹 useReducer 的更多用法


上一篇
Day 21 不管怎樣都用 React.memo 就好了 ?
下一篇
Day 23 useContext + useReducer 管理狀態
系列文
我與 React 的 30天30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言