標籤:

React 高階組件介紹

參考:深入理解 React 高階組件

什麼是高階組件?

一個高階組件只是一個包裝了另外一個 React 組件的 React 組件

這種形式通常實現為一個函數,本質上是一個類工廠(class factory),它下方的函數標籤偽代碼啟發自 Haskell

hocFactory:: W: React.Component => E: React.Component

這裡 W(WrappedComponent) 指被包裝的 React.Component,E(Enhanced Component) 指返回的新的高階 React 組件。

定義中的『包裝』一詞故意被定義的比較模糊,因為它可以指兩件事情:

  1. 屬性代理(Props Proxy):高階組件操控傳遞給 WrappedComponent 的 props,
  2. 反向繼承(Inheritance Inversion):高階組件繼承(extends)WrappedComponent。

我們將討論這兩種形式的更多細節。

我可以使用高階組件做什麼呢?

概括的講,高階組件允許你做:

  • 代碼復用,邏輯抽象,抽離底層準備(bootstrap)代碼
  • 渲染劫持
  • State 抽象和更改
  • Props 更改

高階組件的定義

HoC 不屬於 React 的 API,它是一種實現模式,本質上是一個函數,接受一個或多個 React 組件作為參數,返回一個全新的 React 組件,而不是改造現有的組件,這樣的組件被稱為高階組件。開發過程中,有的功能需要在多個組件類復用時,這時可以創建一個 Hoc。

基本用法

  • 包裹方式

const HoC = (WrappendComponent) => {n const WrappingComponent = (props) => (n <div className="container"> <WrappendComponent {...props} /> </div>n );n return WrappingComponent;n};n

上述代碼中,接受 WrappendComponent 作為參數,此參數就是將要被 HoC 包裝的普通組件,在 render 中包裹一個 div,賦予它 className 屬性,最終產生的 WrappingComponent 和 傳入的 WrappendComponent 是兩個完全不同的組件。

在 WrappingComponent 中,可以讀取、添加、編輯、刪除傳給 WrappendComponent 的 props,也可以用其它元素包裹 WrappendComponent,用來實現封裝樣式、添加布局或其它操作。

  • 組合方式

const HoC = (WrappedComponent, LoginView) => {n const WrappingComponent = () => {n const {user} = this.props; n if (user) {n return <WrappedComponent {...this.props} />n } else {n return <LoginView {...this.props} />n }n };n return WrappingComponent;n};n

上述代碼中有兩個組件,WrappedComponent 和 LoginView,如果傳入的 props 中存在 user,則正常顯示的 WrappedComponent 組件,否則顯示 LoginView 組件,讓用戶去登錄。HoC 傳遞的參數可以為多個,傳遞多個組件定製新組件的行為,例如用戶登錄狀態下顯示主頁面,未登錄顯示登錄界面;在渲染列表時,傳入 List 和 Loading 組件,為新組件添加載入中的行為。

  • 繼承方式

const HoC = (WrappendComponent) => {n class WrappingComponent extends WrappendComponent {n render() (n const {user, ...otherProps} = this.props;n this.props = otherProps;n return super.render();n }n }n return WrappingComponent;n};n

WrappingComponent 是一個新組件,它繼承自 WrappendComponent,共享父級的函數和屬性。可以使用 super.render() 或者 super.componentWillUpdate() 調用父級的生命周期函數,但是這樣會讓兩個組件耦合在一起,降低組件的復用性。

React 中對組件的封裝是按照最小可用單元的思想來進行封裝的,理想情況下,一個組件只做一件事情,符合 OOP 中的單一職責原則。如果需要對組件的功能增強,通過組合的方式或者添加代碼的方式對組件進行增強,而不是修改原有的代碼。

注意事項

  • 不要在 render 函數中使用高階組件

render() {n // 每一次render函數調用都會創建一個新的EnhancedComponent實例 n // EnhancedComponent1 !== EnhancedComponent2 n const EnhancedComponent = enhance(MyComponent);n // 每一次都會使子對象樹完全被卸載或移除 n return <EnhancedComponent />;n}n

React 中的 diff 演算法會比較新舊子對象樹,確定是否更新現有的子對象樹或丟掉現有的子樹並重新掛載。

  • 必須將靜態方法做拷貝

// 定義靜態方法nWrappedComponent.staticMethod = function() {/*...*/}n// 使用高階組件nconst EnhancedComponent = enhance(WrappedComponent);nn// 增強型組件沒有靜態方法ntypeof EnhancedComponent.staticMethod === undefined // truen

  • Refs屬性不能傳遞

HoC中指定的 ref,並不會傳遞到子組件,需要通過回調函數使用 props 傳遞。

參考鏈接

  • 原文:React 高階組件介紹 - 掘金
  • 初識React中的High Order Component
  • 高階組件

推薦閱讀:

Electron 應用實戰 (架構篇)
setState為什麼不會同步更新組件狀態
如何入門 React?你應該跟著這八步走
Redux 的問題:React、MobX 和 Realm 能解決嗎?
組件庫設計實戰 - 國際化方案

TAG:React |