日常開發 React.js 專案的過程中,我們經常會在某個 component 上包裹多層 context provider。這不僅讓程式碼看起來很雜亂,還會帶來維護上的困擾:一旦需要調整 provider 的順序,就得大範圍地修改 JSX 的結構。尤其在專案規模不斷擴大、團隊成員增加時,這一類改動容易導致 git commit 大量有很多行數的改動,進而提高 merge conflict 的風險。
例子:Provider Hell
以下這個例子就展示了典型的「Provider Hell」情境,有一堆的 context provider。當這些 context provider 愈來愈多時,就會導致 DOM 看起來很長很多層。萬一在要改動 context provider 的順序時,就需要同時改動整對的 Opening Tag 和 Closing Tag。
💡
大家看到一個 context provider 重用很多次,但現實應該不會這樣做。這裡是因為舉例方便一些,不至於例子寫太長。💡
我自己的習慣是建立一個 component 在裡面用 context provider,那麼 child component 便在 context 之中。也可以在這個 context component 裡面定義 context provider 的初始值。
解決方案:使用 Higher-Order Component (HOC) 來統一管理多層 provider
為了簡化巢狀結構,我們可以建立一個 HOC wrapper function(withProviders),讓它自動為目標 component 套上多個 context provider。
- 只需將所有 provider 以陣列形式傳入 HOC 即可自動完成巢狀包裹(陣列順序決定包裹層級)。想像 HOC 由陣列的第一個開始,一層層的往外包上 context provider
- 可在不同 component 上重用,程式碼更乾淨整潔。
- 調整順序時只需修改陣列順序,不會造成大規模 JSX 變更,大幅降低 conflict 風險。
HOC 的核心程式碼如下:
用法一:需要動態傳入 value 時(代碼稍長,但彈性高)
用法二:在 provider 內部預先定義好初始 value(代碼最簡潔)
這樣在使用 HOC 時就不需額外傳值,直接放入 provider component 本身即可
📕
後記如果希望在使用 HOC 時仍能動態傳入不同的初始值,用法一的代碼會較長。
若想追求極致簡潔,就採用用法二,但會犧牲部分彈性 (無法在同一 provider 上傳入不同 value)。
當然兩種用法可以混合使用。
另一個小缺點是:難以重用相同 provider 但提供不同 value 的情境——不過在實際專案中,這種需求不常見。
整體而言,這種 HOC 包裹技巧能有效解決多層 context provider 的痛點,讓程式碼更易維護,尤其適合中大型 React 專案使用。
參考
A JavaScript library for building user interfaces