React高阶组件探究

在使用React构建项目的过程中,经常会碰到在不同的组件中需要用到相同功能的情况。不过我们知道,去这些组件中到处编写同样的代码并不优雅。

在以往,为了解决以上的情况,我们会用到Mixin这种方式来解决问题。

以下是一个最为简单的Mixin

var defaultMixin = {getDefaultProps: function() {return {name: "Allen"}}
}var Component = React.createClass({mixins: [defaultMixin],render: function() {return <h1>Hello, {this.props.name}</h1>}
})

这个例子很好理解,在这里就不详述了。要使用mixin属性,我们只需要简单地在组件中加入mixins属性即可。

不过在React ES6中,因为种种原因,mixin将不再被支持。

详情可以参考以下文章:

  1. Mixin已死,Composition 万岁

  2. React官方在ES6中不建议使用mixin

文章中提到用高阶组件来替代mixin
所谓高阶组件其实只是一个方法。这个方法中返回一个包裹着原组件的新组件。接下来看看它的基本用法。

高阶组件基本介绍

function hoc(ComponentClass) {return class HOC extends React.Component {componentDidMount() {console.log("hoc");}render() {return <ComponentClass />}}
}

以上代码可以看作是一个最简的高阶组件

使用起来也很简单,比如有一个React组件。

class ComponentClass extends React.Component {render() {return <div></div>}
}export default hoc(MyComponent);

只需要将你的组件类作为参数传入高阶组件这个方法中即可。

如果采用ES7的decorator语法。则可以更简洁

@hoc
export default class ComponentClass extends React.Component {//...
}

简单来说,高阶组件就是一个函数,它让你传入一个组件类,然后返回给你一个更强大的组件类。

用更生动一点的说法,高阶组件就像是一个buff……

鸡血(大锤)  ===>  打了鸡血的大锤@超级buff
class 赛亚人 {}   //超级赛亚人get~~~

类似以上这种感觉……

高阶组件中的props、ref、state

操作props

你可以在高阶组件中对ComponentClass中的props进行读取、添加、编辑操作。

例子:

function hoc(ComponentClass) {return class HOC extends React.Component {render() {const newProps = {name: "cqm",value: "testData",}return <ComponentClass {...this.props} {...newProps} />}}
}

高阶组件中能够通过this.props直接获取到ComponentClass中的props,假设this.props中有name,那么newProps中的name会覆盖掉this.props中的name。

通过ref访问组件实例

你可以通过ref访问到组件中的实例。可以看以下例子:

function hoc(ComponentClass) {return class HOC extends React.Component {componentDidMount() {console.log(this.refs.componentClass);}render() {return <ComponentClass ref="componentClass" />}}
}

提示:React中ref还有这种回调函数的写法: ref={(dom) => this.dom = dom} 依稀记得好像在哪里看到过,说这种写法更新更好

你也可以使用另一种方式:

function hoc(ComponentClass) {return class HOC extends React.Component {getDom(dom) {console.log(dom);}render() {return <ComponentClass ref={(dom) => this.getDom(dom)} />}}
}

ref回调函数在ComponentClass渲染时执行,从而可以轻松拿到它的引用。

获取state

在高阶组件中获取state有若干种方式,下面将一一阐述。

和React父子组件交互的方式类似,你可以往ComponentClass中传入一个函数,之后ComponentClass中通过props拿到这个函数,往里面传入你想要的state参数。

示例如下:

function hoc(ComponentClass) {return class HOC extends React.Component {getState(state) {console.log(state);}render() {const newProps = {getState: (state) => this.getState(state)};return <ComponentClass {...newProps} />}}
}@hoc
export default class ComponentClass extends React.Component {state = {value = ""};render() {return (<div><input onChange={(z) => this.props.getState(z.target.value)} /></div>);}
}

理论上你还可以通过this.refs.componentClass.state这种方式来获取全部的state(不过我一般不这么干)。


接下来用到的获取state的方式应该算是高阶组件的另一种运用方式

我在文章开篇提到过这句话

所谓高阶组件其实只是一个方法。这个方法中返回一个包裹着原组件的新组件。接下来看看它的基本用法。

高阶组件中所谓的包裹方式主要有以下两种:

  1. Props Proxy: 高阶组件通过ComponentClass中的props来进行相关的操作。

  2. Inheritance Inversion: 高阶组件继承自ComponentClass。

之前我们并未用到第二种包裹方式,大部分采用的Props Proxy的方式来进行操作。接下来我们来详细讲讲第二种方式。

Inheritance Inversion

Inheritance Inversion的最简实现大概如下:

function hoc(ComponentClass) {return class HOC extends ComponentClass {render() {return super.render();}}
}

高阶组件hoc中,返回了一个继承了原先组件类的组件。颇有一种反转的味道。

显而易见,你可以在这个组件类中拿到一切ComponentClass的props、state。

代码如下:

function hoc(ComponentClass) {return class HOC extends ComponentClass {componentDidMount() {console.log(this.state);}render() {return super.render();}}
}@hoc
export default class ComponentClass extends React.Component {state = {id: 0,value: "hahaha"};render() {return <div>ComponentClass</div>}
}

你也可以通过super.[lifecycle]来调取ComponentClass的声明周期或是render函数

接下来我们可以来实现一个简单的需求。比如说一个组件中存在网络请求,你希望在请求完成之前组件显示loading,完成后再显示具体内容。我们就可以运用高阶组件来实现。

function hoc(ComponentClass) {return class HOC extends ComponentClass {render() {if (this.state.success) {return super.render()}return <div>Loading...</div>}}
}@hoc
export default class ComponentClass extends React.Component {state = {success: false,data: null};async componentDidMount() {const result = await fetch(...请求);          this.setState({success: true,data: result.data});}render() {return <div>主要内容</div>}
}

这个例子应该很好理解。这边就不再详细解释了。

Inheritance Inversion渲染劫持

渲染劫持这句话的意思很好理解。因为在高阶组件中你可以控制ComponentClass的渲染输出,因此你可以在渲染的时候做出各种各样的事情。比如修改props,修改render的组件树等等。

以下示例用以演示修改render方法输出的组件树

function hoc(ComponentClass) {return class HOC extends ComponentClass {render() {const elementTree = super.render();elementTree.props.children = elementTree.props.children.filter((z) => {return z.type !== "ul" && z;}const newTree = React.cloneElement(elementTree);return newTree;}}
}@hoc
export default class ComponentClass extends React.Component {render() {const divStyle = {width: '100px',height: '100px',backgroundColor: 'red'};return (<div><p style={{color: 'brown'}}>啦啦啦</p><ul><li>1</li><li>2</li></ul><h1>哈哈哈</h1></div>)}
}

以上就是一个渲染劫持的示例,我将ComponentClass中的ul标签给移除了。你可以使用渲染劫持完成类似的需求。如果你对于React中的组件元素操作不是很了解的话,推荐您去看看官方文档中的这一节:

React官方关于component-elements的文档

实际案例

mobx-react

/**MyStore文件**/
import { observable } from 'mobx';export class MyStore() {@observable value = 1;@action add = () => {this.value++;}
}/**另一个文件**/
import MyStore from './MyStore';const store = new MyStore();@observer
export default class MyComponent extends React.Component {render() {return (<div><p>这只青蛙的寿命{store.value}</p><button onClick={store.add}>+1s</button></div>);}
}

可以把observer当成高阶组件。传入MyComponent这个类,之后mobx-react会对其生命周期进行各种处理,并通过调用实例的forceUpdate来进行刷新实现最小粒度渲染。

算是小小安利一下mobx这个框架吧。

顺便一提, mobx中提倡一份数据引用,而在redux中则更提倡immutable思想,返回新对象。

pure-render-decorator

@pureRender
export default class MyComponent extends React.Component {static propTypes = {name: React.PropTypes.string,};render() {return (<div>{this.props.name}</div>);}
}

pureRender中重新定义了shouldComponentUpdate这一生命周期,当传来的props未发生改变时,不重新render,从而达到性能优化的目的。


以上。。。

References

  1. Mixin的使用
  2. 深入理解React高阶组件
  3. React进阶——使用高阶组件(Higher-order Components)优化你的代码
  4. Mixin 已死,Composition 万岁

React高阶组件探究相关推荐

  1. react实现汉堡_利用 React 高阶组件实现一个面包屑导航

    什么是 React 高阶组件 React 高阶组件就是以高阶函数的方式包裹需要修饰的 React 组件,并返回处理完成后的 React 组件.React 高阶组件在 React 生态中使用的非常频繁, ...

  2. [react] 高阶组件(HOC)有哪些优点和缺点?

    [react] 高阶组件(HOC)有哪些优点和缺点? HOC 优点 通过传递props去影响内层组件的状态,不直接改变内层组件的状态,降低了耦合度 缺点 组件多层嵌套, 增加复杂度与理解成本 ref隔 ...

  3. 「react进阶」一文吃透React高阶组件(HOC)

    一 前言 React高阶组件(HOC),对于很多react开发者来说并不陌生,它是灵活使用react组件的一种技巧,高阶组件本身不是组件,它是一个参数为组件,返回值也是一个组件的函数.高阶作用用于强化 ...

  4. react组件类型及深入理解react高阶组件

    React中常见的组件类型及分类: 1.展示组件(Presentational component) 与 容器组件(Container component) 2.类组件(Class component ...

  5. React高阶组件_阶段1

    react高阶组件_阶段1 作用: 个人总结的高阶组件设计的作用主要有两点, 这里直接使用装饰器方式 非装饰器使用请结合我的博文"react基础梳理_阶段1"中的"自定义 ...

  6. react 高阶组件hoc使用

    react 高阶组件hoc使用 1. 为什么使用高阶组件 2. 具体使用 2.1原代码: 2.2 使用hoc封装后 1. 为什么使用高阶组件 高阶组件(HOC)是 React 中用于复用组件逻辑的一种 ...

  7. 使用react 高阶组件withRouter

    使用react 高阶组件withRouter withRouter 是一个高阶组件,把 match,location,history 三个对象注入到组件的 props 中.这是一个非常实用的函数 re ...

  8. react 高阶组件

    react 高阶组件 概述 目的:实现状态逻辑复用 采用 包装(装饰)模式,比如说:手机壳 手机:获取保护功能 手机壳:提供保护功能 高阶组件就相当于手机壳,通过包装组件,增强组件功能 思路分析 高阶 ...

  9. react高阶组件和hooks

    1. react高阶组件 1.1 高阶组件的概念 高阶组件(Higher Order Component,简称:HOC ): 是 React 中用于重用组件逻辑的高级技术, 它本身不是react中的组 ...

最新文章

  1. 毫末智行,现在是中国营收增速最快的无人车公司
  2. 在物理机上用u盘安装linux遇到的问题
  3. CN.Text开发笔记—利用反射将数据读入实体类
  4. 2、垃圾回收算法(标记清除算法、复制算法、标记整理算法和分代收集算法),各种垃圾收集器讲解(学习笔记)
  5. python json是什么_python json详解
  6. linux的cimserver是什么服务,openpegasus的启动方式(即cimserver的启动方式)
  7. 『HTML5挑战经典』是英雄就下100层-开源讲座(一)从天而降的英雄
  8. Delphi中常用字符串处理函数
  9. radiobutton 设置为不能点击_谷歌要求:安卓 11 相机默认不能设置为“美颜”模式...
  10. python传大文件如何检查遗漏,如何使用Python获取大文件的实时复制进度?
  11. 【全网世界区划最全整理输出之第二部分】全世界所有国家的行政区划整理,省市信息,已按照国家,省,市排好序,可直接复制使用,第二部分到8167行,总条数:21088
  12. 光纤中传导模式matlab仿真,光纤通信实验指导书
  13. ansys经典界面分析工字钢_ANSYS经典界面讲解.ppt
  14. 触发器:建立时间和保持时间
  15. matlab仿真平台式惯导
  16. 一点计算机电脑就闪,电脑启动有点闪烁是怎么回事
  17. deepin-wine的安装
  18. body 没有被撑开_flex布局被子元素撑开如何保持内容不超出容器的方法
  19. ac管理器管理员密码忘记了_人们为什么不使用密码管理器
  20. 学习python第五天

热门文章

  1. leetcode:32. 最长有效括号
  2. Hive 多列转行 (if函数)
  3. Java学习:MyEclipse下载以及安装步骤,详细贴图每一个步骤,包教包会
  4. 学习巴菲特的正确姿势
  5. mht文件转为html文件(javax.mail方式)
  6. C# (江湖熟手)- 串口设备对接
  7. 我是深圳南山的集体户口 要将我老婆的户口随迁入深圳 没有房产 可以办深圳人才中心的集体户口吗
  8. 广西机电职院计算机系,广西机电职院崇左东盟学院办学点揭牌仪式暨2019级大专班开学典礼在东盟学院隆重举行...
  9. 第九天javaSE基础(学生管理系统)
  10. 讲座报名 | 清华大学副教授刘知远:大模型十问