回來填坑。
簡述
之前碰到這個 hook 時就想說等學完 Redux 再來詳細解說吧,結果一眨眼兩、三個月就過去了 XD,總之這篇要來解釋一下 useReducer
的用途。
我覺得當這個 hook 很適合用在「當你不需要用到 Redux,但又想要全域 state」的時候。可以利用它來跟 Context
結合出一個替代方案。
所以看這篇前最好先知道一下 useContext
在幹嘛?因為等一下的範例會用到,建議可以先去看我之前寫的這兩篇:
useReducer 的好用之處?
「在學任何東西前,先問一下為什麼要用這個東西?」是句很經典的話,所以我們先來舉一個範例,一開始不使用 useReducer
接著再來解釋如果用了 useReducer
能帶來什麼好處?
假設我們目前要做一個可以切換「顏色主題」的網頁,底下的元件得根據目前的主題來切換樣式,所以除了需要 state 以外,我們還需要一個 Context
來避免「Props drilling」的問題。
所以呢,目前大概會有這樣的 code:
ThemeContext.jsx
1 | import { createContext } from 'react' |
這個是在 React-關於 useContext 更好的寫法 中提到的小技巧,忘記的話可以去複習一下。
App.js
1 | import Nav from "./Nav"; |
接著,假設我們想透過導覽列上的按鈕來切換顏色,可能就會寫出這樣的東西:
1 | import { useContext } from "react"; |
做到這邊有任何疑問的話可以先來這邊看一下範例,希望能幫助你理解一點。
總之呢,一個最簡單的 Context 就這樣完成了,但如果你仔細想一下會發現其實有可以改善的空間:
1. 邏輯全部塞在 function 裡
我知道這聽起來有點奇怪,畢竟在 function 放邏輯不是天經地義的事嗎?不然要放在哪裡?
別急,我的意思是指剛剛我們直接在 changeTheme
中用 setTheme
的這種方式其實應該有更好的寫法,畢竟當邏輯變得複雜時裡面的東西也會越來越多,可讀性就會沒那麼好。
這個時候如果我們可以透過 dispatch
的概念來改寫的話,不是會好很多嗎?像這樣:
1 | function changeTheme () { |
2. state / function 零散各地
意思是當 ThemeContext
想建立其他的 state 時,state 就會越來越多個,像這樣:
1 | import { createContext } from 'react' |
所以呢,這時候如果改用 useReducer
的話就可以改善這些問題。
加入 useReducer
這邊先介紹一下 useReducer
的用法,其實就跟在寫 redux 差不多,所以如果你對 redux 完全沒概念的話建議先去補一些相關知識再回來看,這邊不會解釋太深。
總之核心要素還是幾個東西:
- reducer
- action
- dispatch
首先 useReducer
會接收兩個參數,分別為 initialState
跟 reducer
。
initialState
就是初始的 state,reducer
則是用來處理每個 action 的 function。
所以強調一下:
reducer
就只是一個 functionreducer
就只是一個 functionreducer
就只是一個 function
接著 useReducer
會回傳兩個值(包在 Array 裡),分別為 state
跟 dispatch
,前者就是 state 的值,後者則是用來發出 action 的一個 function。
其實這幾個東西都是 redux 的核心要素,所以再次建議你先去理解 redux 的概念後再回來看這篇,不然應該很難理解。
所以回到剛剛的例子,我們會把 useState
拿掉,改用 useReducer
來取代,變成這樣子:
1 | import { createContext, useReducer } from "react"; |
最後完成的 範例 在這邊,有什麼疑問的話可以去玩玩看。
回顧一下剛剛提到的兩個問題,這邊改用 useReducer
後其實就都解決了:
1. 邏輯都寫在 function 裡
現在 function 要做的事情很單純,就是 dispatch
一個 action 給 reducer,僅此而已。
2. 需要很多不同的 state 來管理不同狀態
當改用 useReducer
後,我們可以把所有 state 放在一個 Object 管理就好,不需要再拆成一個一個。
所以以上就是 useReducer
的範例,希望之後能運用這個輕量型的 hook 來實現簡單的狀態管理。