Higher-order Components 高階組件

原文來(lái)自 https://gist.github.com/sebmarkbage/ef0bf1f338a7182b6775

import { Component } from "React" ;

export const Enhance = (ComposedComponent) => class extends Component {
    constructor() {
        this.state = { data: null };
    }
    componentDidMount() {
        this.setState({ data: 'Hello' });
    }
    render() {
        return <ComposedComponent {...this.props} data={this.state.data} />;
    }
};

Enhance 是一個(gè)方法,當(dāng)傳入一個(gè) Component(ComposedComponent) 的時(shí)候,它將自動(dòng)為該 Component 進(jìn)行擴(kuò)展并返回新的類定義。上例中,就返回了一個(gè)擴(kuò)展的 Component 類,為構(gòu)造函數(shù)中添加了 state,也在 React 生命周期函數(shù) componentDidMount中添加了處理邏輯,而 render 方法則使用了傳入的參數(shù),完成了渲染。

新的業(yè)務(wù)邏輯由 Enhance 提供(通過(guò)返回新的 Component),傳入的 ComposedComponent 就像一個(gè)回調(diào)函數(shù)。看看怎么使用:

import  { Component }  from "React";
import { Enhance } from "./Enhance";

class MyComponent = class extends Component {
      render() {
          if (!this.props.data) return <div>Waiting...</div>;
          return <div>{this.data}</div>;
      }
}

export default Enhance(MyComponent); // Enhanced component`

MyComponent 就是一個(gè)高階組件(類似于高階函數(shù)-回調(diào)函數(shù)),負(fù)責(zé)對(duì)特定的數(shù)據(jù)進(jìn)行渲染。MyComponent 僅僅知道別人會(huì)把數(shù)據(jù)通過(guò) this.prop.data 傳進(jìn)來(lái),其他就都不關(guān)心了。可以看到,和 Mixins 的擴(kuò)展方式相比,MyComponent 的工作要輕松很多。

Mixins

在 React 中,Mixins 是傳統(tǒng)的為 Component 進(jìn)行擴(kuò)展的做法。Mixins 的做法很像傳統(tǒng)的命令式編程,即要擴(kuò)展的組件決定需要哪些擴(kuò)展(Mixins),以及了解所有擴(kuò)展(Mixins)的細(xì)節(jié),從而避免狀態(tài)污染。當(dāng) Mixins 多了之后,被擴(kuò)展組件需要維護(hù)的狀態(tài)和掌握的”知識(shí)”越來(lái)越多,因此也就越來(lái)越難維護(hù),因?yàn)樨?zé)任都被交給了”最后一棒”(Last Responsible Moment)。

而高階組件的思路則是函數(shù)式的,每一個(gè)擴(kuò)展(Enhance)就是一個(gè)函數(shù),接受要擴(kuò)展的組件作為參數(shù)。如果要進(jìn)行 3 個(gè)擴(kuò)展,那么則可以級(jí)聯(lián),看起來(lái)就是:

const newComponent = Enhance3(Enhance2(Enhance1(MyComponent)));

高階組件的方式則使得每一個(gè) Enhance 以及被擴(kuò)展的組件都只關(guān)心自己手里那點(diǎn)事。Enhance 不知道別人會(huì)怎么用它,被擴(kuò)展的組件也不關(guān)心別人會(huì)怎么擴(kuò)展它。負(fù)責(zé)人是那個(gè)將它們連在一起的”水管工”,即最后寫串聯(lián)代碼的人。

高階組件的用法雖然用到了 ES6 的類繼承,但是實(shí)際上卻只是把它當(dāng)個(gè)工具使用,而不是真的借助于 OO 的繼承。在 React 中使用高階組件部分替代 Mixins,仍然是非常函數(shù)化的思維方式,即針對(duì) ”***轉(zhuǎn)換” ***編程。只不過(guò)是組件定義替代了函數(shù)而已。

Decorators

除了函數(shù)方式擴(kuò)展,通過(guò) ES7 草案中的 Decorator(https://medium.com/google-developers/exploring-es7-decorators-76ecb65fb841) 也是可以的。Decorator 可以通過(guò)返回特定的 descriptor 來(lái)”修飾” 類屬性,也可以直接”修飾”一個(gè)類。即傳入一個(gè)已有的類,通過(guò) Decorator 函數(shù)”修飾”成了一個(gè)新的類。那么我們之前的 Enhance 方法就可以直接被當(dāng)成 Decorator 來(lái)用了。

import { Component } from "react";
import { Enhance } from "./Enhance";

@Enhance
class MyComponent extends Component {
  render() {
    if (!this.data) return <div>Waiting...</div>;
    return <div>{this.data}</div>;
  }
}

export default MyComponent; // Enhanced component

用或不用 Decorator,只是習(xí)慣問(wèn)題。

一個(gè)真實(shí)世界的 Enhance 的例子(https://github.com/kriasoft/react-decorators)

用法代碼如下:

import React from 'react';
import withViewport from 'react-decorators/withViewport';

@withViewport
class MyComponent {
  render() {
    let { width, height } = this.props.viewport;
    return <div>Viewport: {width + 'x' + height}</div>;
  }
}

React.render(<MyComponent />, document.body);

withView 是一個(gè) Enhance 函數(shù),或者 Class Decorator,傳入一個(gè)被擴(kuò)展組件(MyComponent),返回一個(gè)新的組件。新組建具有獲取窗口尺寸變化的能力(viewport),并且將viewport 通過(guò) this.props.viewport 傳遞給被擴(kuò)展組件(MyComponent)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容