Higher-order Components 高阶组件

原文来自 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 是一个方法,当传入一个 Component(ComposedComponent) 的时候,它将自动为该 Component 进行扩展并返回新的类定义。上例中,就返回了一个扩展的 Component 类,为构造函数中添加了 state,也在 React 生命周期函数 componentDidMount中添加了处理逻辑,而 render 方法则使用了传入的参数,完成了渲染。

新的业务逻辑由 Enhance 提供(通过返回新的 Component),传入的 ComposedComponent 就像一个回调函数。看看怎么使用:

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 就是一个高阶组件(类似于高阶函数-回调函数),负责对特定的数据进行渲染。MyComponent 仅仅知道别人会把数据通过 this.prop.data 传进来,其他就都不关心了。可以看到,和 Mixins 的扩展方式相比,MyComponent 的工作要轻松很多。

Mixins

在 React 中,Mixins 是传统的为 Component 进行扩展的做法。Mixins 的做法很像传统的命令式编程,即要扩展的组件决定需要哪些扩展(Mixins),以及了解所有扩展(Mixins)的细节,从而避免状态污染。当 Mixins 多了之后,被扩展组件需要维护的状态和掌握的”知识”越来越多,因此也就越来越难维护,因为责任都被交给了”最后一棒”(Last Responsible Moment)。

而高阶组件的思路则是函数式的,每一个扩展(Enhance)就是一个函数,接受要扩展的组件作为参数。如果要进行 3 个扩展,那么则可以级联,看起来就是:

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

高阶组件的方式则使得每一个 Enhance 以及被扩展的组件都只关心自己手里那点事。Enhance 不知道别人会怎么用它,被扩展的组件也不关心别人会怎么扩展它。负责人是那个将它们连在一起的”水管工”,即最后写串联代码的人。

高阶组件的用法虽然用到了 ES6 的类继承,但是实际上却只是把它当个工具使用,而不是真的借助于 OO 的继承。在 React 中使用高阶组件部分替代 Mixins,仍然是非常函数化的思维方式,即针对 ”***转换” ***编程。只不过是组件定义替代了函数而已。

Decorators

除了函数方式扩展,通过 ES7 草案中的 Decorator(https://medium.com/google-developers/exploring-es7-decorators-76ecb65fb841) 也是可以的。Decorator 可以通过返回特定的 descriptor 来”修饰” 类属性,也可以直接”修饰”一个类。即传入一个已有的类,通过 Decorator 函数”修饰”成了一个新的类。那么我们之前的 Enhance 方法就可以直接被当成 Decorator 来用了。

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,只是习惯问题。

一个真实世界的 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 是一个 Enhance 函数,或者 Class Decorator,传入一个被扩展组件(MyComponent),返回一个新的组件。新组建具有获取窗口尺寸变化的能力(viewport),并且将viewport 通过 this.props.viewport 传递给被扩展组件(MyComponent)。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,688评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,559评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,749评论 0 226
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,581评论 0 191
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,741评论 3 271
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,684评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,122评论 2 292
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,847评论 0 182
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,441评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,939评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,333评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,783评论 2 236
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,275评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,830评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,444评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,553评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,618评论 2 249

推荐阅读更多精彩内容