iT邦幫忙

2022 iThome 鐵人賽

DAY 6
1
Modern Web

前端技能樹的十萬個為什麼系列 第 6

Day 6 - 為什麼要用 React Hooks

  • 分享至 

  • xImage
  •  

前言

React Hooks 已經出現好一陣子了,現在初學 React 的新手,可能都已經用 hook 用得很順手了。

但如果接手到比較舊一點的 React 專案,可能還會看到以 Class 為主體的 component,那 Class 與 functional component 差在哪裡呢?為什麼現在都直接無腦使用 React hook 了呢?

先想一下

  • React Hooks 是在什麼樣的時代誕生的?
  • React Hooks 怎麼解決問題?
  • React Hooks 的優缺點是什麼?
  • React Hooks 適合什麼情境?

React Hooks 是在什麼樣的時代誕生的?

React 是一個元件導向的 view library,在 v16.8 之前一直都是用 Class 來組織元件,然後用一個個元件排列組合,組成元件樹,完成期待的畫面呈現。

而在元件與元件之間的溝通,往往也可以透過單純的父子 props 傳遞,或者 HOC (higher-order components)、context 等方式。

同時,Class 元件自身也可以擁有自己的 state,也就是 this.state,達成簡易的封裝與狀態管理的功能。

聽起來 Class component 已經夠棒了,然而 Redux 的作者 Dan Abramov 提到

However, we often can’t break complex components down any further because the logic is stateful and can’t be extracted to a function or another component.

  • 大型的 Class component 很難拆分、重構與測試
  • 多個 Class component 可能會需要共用同一段商業或 UI 邏輯(比如放在 componentDidUpdate 裡面的那種),但很難被拉出來共用
  • 承上,Class component 如果要共用,要用較複雜的 pattern,比如 render propsHOC

通常要共用會採用 HOC,也就是會看到類似這種東西:

withAuth(withRouter(withUserStatus(UserDetail)))

除了可讀性的問題以外,這樣層層傳遞的 props,真正到達要使用的層級時,也可能發生 props 丟失或不如預期的結果,這一切問題的矛頭都指向 「階層架構」與「共用」

React Hooks 怎麼解決問題?

Hook 是 React v16.8 中增加的新功能,就像「鉤子」一樣,可以「鉤」在 function-base 的 component 上,不必寫 Class 就能使用 state 以及其他 React 的功能

因此,一些基本的內建 hook:

  • useState 用來代替 Class 裡面用到的 this.state
  • useEffect 用來代替 Class 裡面的生命週期 componentDidMountcomponentDidUpdatecomponentWillUnmount
  • useMemo 用來代替 Class 裡面的 shouldComponentUpdate

甚至,因為 hook 的本質就是 function,所以也可以寫自定義的 hook,感覺其實就像自己定義一個 function 一樣。

就是這關鍵的功能,解決了上述提到的問題,成功把需要共用的商業或 UI 邏輯,包成一個共用的 hook(可以想像成共用的 function),使用起來也像在 call function 一樣。

而重點是,使用 hook 無關乎階層架構的問題,就跟 function 一樣想怎麼用就怎麼用,讓維護程式碼的難度下降不少。

不過 hook 畢竟還是跟一般的 function 不一樣,它有一些使用規則:

使用規則

  1. 只能在 React function component 或是自定義的 hook 中使用,不能在一般的 JavaScript function 中使用。
  2. 只能在 React function component 最上層直接呼叫,不能在條件式、迴圈或巢狀函式內呼叫 hook。

React 使用這些規則來保證每次 render 時,呼叫 hook 的順序都是一樣的

為什麼要確保 hook 順序一樣呢?

官網的解說可以參考這篇,以及這篇,大致上是因為,每一個 component 有一個「memory cell」的內部列表,而這個列表需要根據 index 來找到對應的值,當我們呼叫 useState 這種 hook 的時候,會按照 hook 的順序到列表取得對應的 local state,因此如果 hook 沒有按照順序,就會導致取到錯誤的值。

React Hooks 的優缺點是什麼?

優點

  • 善於拆解大型 component,容易抽出 stateful 的共用邏輯
  • 由於是 function-base,較接近原生的 js 寫法,對於不熟 Class 與 this 的初學者較為友善
  • 承上,比起 class-base,function-base 的程式碼較容易被壓縮和最佳化
  • 使用相對簡單的寫法,像 Redux 的 useSelector 就取代了 connectmapStateToProps

缺點

  • 學習曲線高一些,或者說需要轉換到 hook 思維,比如 useEffect 整合了原先三種生命週期(componentDidMountcomponentDidUpdatecomponentWillUnmount)的功能,如果沒用好反而會出現意料之外的 bug

React Hooks 適合什麼情境?

上述提到的缺點其實也不是太嚴重,比如 useEffect 只要遵循單一職責原則,一個 useEffect 只做一件事,並且正確理解第二個參數 dependency array,其實也不用太擔心。

React hook 的出現,最主要的目的仍在於「拆分」,不管要拆的是重複的元件還是純商業邏輯,只要盡可能讓粒度最小化,各功能職責單一,這樣不僅容易組裝,也方便測試。

結語

心智圖放大版

由於我初次學習 React 的時間點,剛好就介於「class component 獨佔」與「hook 要紅起來」之間,一個尷尬的時間點。

當我好不容易搞懂生命週期,能夠正常維護一個 Class component 了,突然半路就殺出一個 hook!從此我又進入 useEffect 以及它的 dependency 迷陣中。

因此我滿能體會轉移到 hook 思維,過程中的學習曲線真的是滿不容易的,甚至可能比從沒學過 react 的人還要難QQ

不過現在兩邊都懂了之後,覺得嗯。。。還是 hook 寫起來快樂一點XD"

參考資料

React hooks 介紹
Making Sense of React Hooks
知乎 - 談談 React hooks 的優缺點
知乎 - React 為什麼需要 hook


上一篇
Day 5 - 為什麼要用 React
下一篇
Day 7 - 為什麼要用 Redux
系列文
前端技能樹的十萬個為什麼30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言