【温故知新】梳理React中HOC的点点滴滴
前言
由于不可避免的遺忘曲線和最初潦草學習等諸多因素,我獲得的某些技術點會存在沒有吃透或者出現了被遺忘的情況。幸運的是,我有經驗積累這個增益buff,能夠不時的有新的開發思路誕生。
此消彼長,也不是長久之計。于是我想通過溫故知新的方式,重拾部分技術知識或者提煉一些有趣的“奇思妙想”。
本篇主要重新梳理一下React的HOC。
溫故而知新,可以為師矣。
帶著問題去尋找答案
如果我還是單純的看一遍文檔,到最后估計收獲不大。所以,我在開始前,列了一些自己的疑問以及帶著這些疑問要找到答案。
- 為什么提起HOC總會看到Mixins的身影?
- 橫切關注點到底是什么?為什么文檔里面提到HOC解決了橫切關注點問題?
- React為什么用HOC替代Mixins?
- 為什么我平時用不上HOC?
- 我怎樣才能用的上HOC?
…
HOC和它的兄弟Mixins
先來聊一下HOC和Mixins這對兄弟的前情提要。
為了解決橫切關注點問題,早先React也是采用Mixins方式,但是隨著組件的增加,Mixins方式帶來了一系列的問題,比如隱式依賴、名稱沖突、代碼復雜性增加等。
所以React采用HOC的設計模式替代Mixins解決橫切關注問題。
名詞解釋時間
橫切關注點
React文檔里面提到
如果完全不同的組件有相似的功能,這就會產生“橫切關注點(cross-cutting concerns)“問題。
知乎文章 《面向對象困境之 —— 橫切關注點》 ,介紹了關注點和橫切關注點,并舉了日志功能的例子,寫的非常好,我把前面的介紹貼出來,幫助大家更好理解。
什么是關注點(Concern)?
A Concern is a term that refers to a part of the system divided on the basis of the functionality.
關注點是指基于功能劃分系統的一部分。
什么是橫切關注點(Crosscutting Concern)?
部分關注點「橫切」程序代碼中的數個模塊,即在多個模塊中都有出現,它們即被稱作「橫切關注點(Cross-cutting concerns, Horizontal concerns)」。
這樣說好像還是特別抽象?那我們舉個例子。
日志功能就是橫切關注點的一個典型案例。日志功能往往橫跨系統中的每個業務模塊,即“橫切”所有需要日志功能的類和方法體。所以我們說日志成為了橫切整個系統對象結構的關注點 —— 也就叫做橫切關注點啦。
解決橫切關注點不是提煉某個公共方法那么簡單,公共方法具有功能的完整性,如果想要適配所有的業務模塊,隨著業務的迭代,公共方法中的代碼會越來越復雜。所以Vue框架中采用Mixins功能,React使用HOC替換Mixins來解決橫切關注點問題。
Mixins
Vue官網中對 mixins介 紹如下
混入 (mixin) 提供了一種非常靈活的方式,來分發 Vue 組件中的可復用功能。一個混入對象可以包含任意組件選項。當組件使用混入對象時,所有混入對象的選項將被“混合”進入該組件本身的選項。
官網例子
// 定義一個混入對象 var myMixin = {created: function () {this.hello()},methods: {hello: function () {console.log('hello from mixin!')}} }// 定義一個使用混入對象的組件 var Component = Vue.extend({mixins: [myMixin] })var component = new Component() // => "hello from mixin!"上面的例子通過mixins方式將對象myMixin的方法添加到Component組件上去。
HOC
React官網對HOC介紹如下
高階組件(HOC)是 React 中用于復用組件邏輯的一種高級技巧。HOC 自身不是 React API 的一部分,它是一種基于 React 的組合特性而形成的設計模式。
具體而言,高階組件是參數為組件,返回值為新組件的函數。
從這兩段話中,我們不難提煉出復用組件、高級技巧、設計模式、參數為組件、返回為新組件的函數等關鍵詞,發散一下思維,HOC允許開發者在定義一個特定的地方定義某個邏輯,并在許多組件之間共享它,進而解決橫切關注點的問題。
Mixins和HOC,為什么React選擇了后者?
Mixins的誕生很好的幫助解決了功能復用的問題,但是隨著時間的推移,Mixins也逐漸暴露出它的短板。
Mixins的短板
React對于Mixins帶來的麻煩,有一篇文章(文章地址)進行了詳細的介紹,簡單總結為一下幾點。
引入隱式依賴
JavaScript 是一種動態語言,因此很難強制執行或記錄這些依賴關系。一般組件可以引入多個mixin,所以在使用某個mixin中的方法時,其實并不能夠區分是使用的哪個mixin的方法,一旦有人移除了某個被引用的方法,而沒有將所有依賴該方法的地方修改成正確的依賴,原本正常的功能就會發生錯誤。
這些隱含的依賴關系會給開發增加難度。
導致名稱沖突
不能保證兩個特定的 mixin 可以一起使用。例如,如果 FluxListenerMixin 定義了 handleChange(),而 WindowSizeMixin 定義了 handleChange(),則不能一起使用。也不能在自己的組件上定義具有此名稱的方法。
另外,如果與第三方包中的 mixin 有名稱沖突,不能只重命名它的方法。相反,必須在組件上使用笨拙的方法名稱以避免沖突。
導致復雜性滾雪球
即使 mixin 一開始很簡單,但隨著時間的推移,它們往往會變得復雜。
一個mixin可以被多個組件引入,導致使用相同 mixin 的組件變得越來越耦合。任何新功能都會被添加到使用該 mixin 的所有組件中。如果不復制代碼或在 mixin 之間引入更多的依賴關系和間接性,就無法拆分 mixin 的“更簡單”部分,也就導致mixin的復雜性越來越高。
HOC是怎么做的?
為了解決功能復用問題,同時為了規避Mixins產生的問題,HOC做了以下設計。
透傳props
將與HOC自身無關的props透傳,提升使用的靈活性,降低組件間的耦合性。
組合HOC
將HOC與容器組件組合,不直接修改傳入組件的HOC,避免引入隱式依賴。
最大化可組合性
HOC可以接收多個參數,這樣可以降低單一參數帶了的功能復雜性不斷增加的問題。
HOC的實際應用
名將的歸宿是戰場,技術的歸宿是實踐。
通過探索HOC的實際應用,也能能幫助解決“為什么我平時用不上HOC?”和“我怎樣才能用的上HOC?”兩個疑問。
我先想明白了為什么我平時用不上HOC
因為我沒有跳出思維定式的圈子,在早期的業務開發中,更多的是封裝完整的功能組件,對于高階組件沒有理解的很透徹,一方面是不知道用在哪,另一方面是使用了可能也沒有想到這種設計模式就是HOC。
所以,我后來就開始注意,在實際開發中,哪些能用HOC,以及使用之后,是否開發效率和代碼可維護性變的更高。
哪些功能可以讓你用上HOC
一通百通,一悟千悟。
我將項目中用到HOC的功能進行了整理歸納,大致有以下應用場景。
注:是項目中用到的,并不全是我一個人開發的,有很多是我同事的智慧。
按鈕權限控制
按鈕權限控制幾乎是后臺管理系統必備的功能。
功能分析
用一句話概括一個基礎的按鈕權限控制功能,即不同角色用戶可進行的頁面操作可通過數據配置進行控制。
功能實現
新增了PowerButton組件
- 因為每個頁面的每個按鈕都需要加權限控制,所以使用組合的方式,將權限組件包裹在按鈕容器外側達到控制的目的;
- 緩存權限控制按鈕數據,方便統一管理,該數據為頁面pathname對應權限按鈕數組的枚舉;
- 獲取權限控制按鈕數據,獲取緩存中powerButtonData的值和當前頁面的pathname,進而獲取當前頁面的權限按鈕數組;
- 獲取當前按鈕的code值在權限按鈕數組中的索引。如果索引值大于-1表示當前按鈕存在,頁面也會展示按鈕;反之則表示按鈕不存在,頁面不會展示該按鈕;
頁面使用
我們目前使用的中文字符做為按鈕的唯一值,這樣方便業務方在后臺配置每個頁面的按鈕權限。如果有英文字符容易配錯。
import { PowerButton } from '@/components';<PowerButton code='新增'><Button type='primary'>新增</Button> </PowerButton>頁面鑒權
ToC的業務,總少不了對于用戶登錄的處理功能,主要在于某些頁面信息必須等拿到用戶登錄的信息之后才能正常的展示,比如用戶的訂單信息、收獲地址,但是一些頁面不需要用戶登錄也可以正常在用戶的設備上展示,比如首頁、商品詳情頁等。這個時候就需要對頁面權限做處理頁就是我們常說的頁面鑒權功能。
功能分析
- 用戶在進入不需要登錄鑒權的頁面時,會直接打開頁面,設備上展示完整的頁面內容;
- 用戶在進入需要登錄鑒權的頁面時,前端會進行路由攔截(整個處理過程用戶無感知),內部處理判斷登錄的邏輯,如果已登錄直接進入頁面,如果未登錄進入登錄頁,登錄成功之后再進入頁面;
功能實現
新增Authority組件
/*** @description 頁面鑒權*/ import React, { Component } from 'react'; import { Route, Redirect } from 'react-router-dom';class Authority extends Component {constructor(props) {super(props);}/*** 重定向方法* @param {string} path 需要重定向的地址* @return {void} 無*/redirect(path) {let { pathname, search } = this.props.location;// 重定向指定pathreturn <Redirect to={path} />;}render() {const { path, component } = this.props;const { pathname, search } = this.props.location;let query = decodeQuery(search);// =>true: 如果沒有用戶信息,跳轉登錄頁if (!sessionStorage.member) return this.redirect('/login');return <Route path={path} component={component} />;} }export default Authority;頁面使用
- 不需要鑒權的頁面模塊,會直接進行路由跳轉;
- 需要鑒權的頁面模塊,使用Authority組件進行鑒權處理;
總結
上面HOC的實際應用,是否覺得功能挺眼熟的,空閑的時候,不妨捋捋自己項目的代碼,沒準會有不錯的收獲。
文章寫的很基礎,是因為作者本人還處于不斷學習的階段。不過溫故確實能夠知新。
雖然作者本人的功力還沒有足夠深厚,但是正在通過溫習學習收獲成長。希望未來奔跑著,能追上一些大佬的背影。
總結
以上是生活随笔為你收集整理的【温故知新】梳理React中HOC的点点滴滴的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: idea项目总是自动重启_IDEA 下
- 下一篇: 举头望明月打计算机术语,呐,你们要的灯谜