React Hooks 之於 HoC 與 Render Props
在此之前,不瞭解 HoC 的同學請看高階元件 - React,不瞭解 Render Props 的同學請看Render Props - React,都是官方文件,我貼的都是翻譯連結。
總的來說,HoC 與 Render Props 都是不錯的 React 或者 VDOM 框架中的程式碼組合思路,但現在 React 生態顯然有了新歡: HooksIntroducing Hooks - React 。具體 Hooks 是怎麼玩的就不解釋了。
Hooks 的出現使得原本很多很彆扭的寫法變得輕鬆,典型就是他可以取代掉 class 生命週期中大多數的功能,把更相關的邏輯放在一起,而非零散在各個生命週期例項方法中。
但也開始有了另一個問題:Do Hooks replace render props and higher-order components?
官方的回答說,在 HoC 或者 Render Props 只有一個 child 的情況下通常 hooks 是一個更簡單的提供的方式。但我想,我們可以再深挖一下。
在 Hooks 之前,如果要做不同注入資料/狀態之間的計算是挺操蛋的。
HoC 方案的典型思路是,在對原檢視進行多次的 decorate 之後,再進行 mapProps 處理,將前面的多個數據進行一次中心化的計算。這是個特別函式式的操作,可能有一定的門檻;而且,這種方式的確與 render 距離太遠了,以至於在 class 內部可能都得糾結一下各個 props 究竟是來自於哪裡,如果有問題、問題又出自於哪裡。
而另一種思路則是 Render Props, 就是把 HoC 包裝為一個 JSX 元件,通過 function children 或者 render props 將狀態遞交給下一層,典型就像 motion 庫中做的那樣;問題就在於如果有很多的元件依賴,就會一層套一層地形成 JSX 中的巢狀地獄。而且,這種方式顯然太深入到 render 過程中了,一些簡單的操作卻需要巢狀一層 JSX 也是挺痛苦的。
而上面不管是哪種方式,都還是將各個資料 / 狀態之間的關係給拉遠了。
Hooks 就解決了這個問題,就像 async / await 之於 Promise 的關係那樣。
但這顯然並不意味著 Hooks 就能取代了 HoC 以及 Render Props,因為他們其實還是有著各自的優勢所在。
- HoC 可以做到很輕鬆地外部協議化注入 功能到一個基礎 Component 中,所以可以用來做外掛。就像 react-swipeable-views 中的 autoPlay HoC 那樣,這個功能特性直接放到主庫裡面感覺不太合適,但可以通過注入狀態化的 props 的方式進行擴充套件。這種特性使得 HoC 特別適合用來做基礎元件的外掛 ,也適合用於做 Adapter 層。而反觀 Hooks 中間的處理過程則一定會與目標元件強依賴。這不是 Hooks 的缺陷,但 Hooks 顯然並不是設計來進行外掛注入的。
- HoC 的方式可以天然地進行元件的分層以及組合 ,並且這種分層基本都可以描述為狀態注入以及 props mapping 的過程。並且,這個分層過程可以描述為函式式的 compose,這對於其中的配置及順序管理非常有利。
- 而看看 Render Props,其使用時天然的就是 JSX 的一部分,那就意味著他JSX 中的邏輯計算來進行其中引數的管控,也可以通過 VDOM 中的 diff 特性提供效能上的優化。雖然巢狀地獄似乎不是什麼好事,但樹狀結構 本身就是巢狀的,XML Like 的語法卻依然更合適用於描述樹狀結構以及其中的決策過程。
- Render Props 還是非常天然而簡單的邏輯,在其中可以放心大膽地進行各種 map, if-else, && 等各類操作。而 Hooks 卻不是,他的設計機制使得使用起來與呼叫順序強相關,那限制就多。
所以,Hooks 個人看來更多是對原有的 HoC 以及 Render Props 方案的補充 ,填補了原本兩邊都不擅長的部分。他的寫法天然地可以讓程式碼更加緊湊,更適合做Controller 或者需要內聚 的相關邏輯。
總結下:
- Hooks 可以優化 render 的前置邏輯處理,也適合用於取代 class extend 的寫法;
- HoC 更多是個從外注入的方案,也適合用來做外掛;
- Render Props 可以在樹狀 VDOM 的渲染流程上有更多的自由度;
當然 Hooks 依然被賦予了極高的價值,因為,我為何不能用 Hooks 的方式來寫 HoC 以及 Render Props? 這中間具體的使用,有著極高的靈活性,需要根據具體情況具體分析。