原文链接:https://segmentfault.com/a/1190000010371752
知识
高阶组件:他描述得是接受react组件作为输入,输出一个新的react组件。
更通俗的讲:高阶组件是通过包裹(wrapped)被传入的react组件,经过一系列处理最终返回一个相对增强(enhanced)的React组件,供其他组件调用。
实现一个高阶组件
- 下面我们来实现一个最简单的高阶组件(函数),它接受一个React组件(WrappedComponent),包裹后然后返回。
import React, {Component} from 'react';
export default function widthDemo1(WrappedComponent) {
return class HOC extends Component {
render() {
return <div>
<div className="demo-header">
我是普通组件的标题-高阶组件
</div>
<WrappedComponent {...this.props}/>
</div>
}
}
}
- 在其他组件里,我们引用这个高阶组件,用来强化它。
@widthDemo1
export default class Demo extends Component {
render() {
return (
<div>
我是一个普通组件
</div>
);
}
}
在这个简单的例子里面,高阶函数就做了一件事,那就是为包裹的组件添加了一个标题。这个高阶组件可以用到任何一个乣添加此逻辑的组件上面,只需要被此高阶组件装饰即可。
高阶组件的进阶
组件参数
还是以上述例子为例,此高阶组件仅仅只是展示了我是标题这个名称,但是为了更好的抽象,此标题应当可以被参数化,如下方式调用。
// 如果传入参数,则传入的参数将作为组件的标题呈现
import React, { Component } from 'react';
import widthDemo1 from './demo-1';
@widthDemo1('我是普通组件的标题-高阶组件demo')
export default class Demo1 extends Component {
render() {
return (
<div>
我是一个正常普通组件
</div>
);
}
}
widthDemo1需要被改写成如下形式,它接受一个参数,然后返回一个高阶组件(函数)。
import React, {Component} from 'react';
function getDisplayName(component) {
return component.displayName || component.name || 'Component';
}
export default function (title){
return function widthDemo1(WrappedComponent) {
return class HOC extends Component {
// static displayName = `HOC(${getDisplayName(WrappedComponent)})`
render() {
return <div>
<div className="demo-header">
{title}
</div>
<WrappedComponent {...this.props}/>
</div>
}
}
}
}
使用Es6写法更简单
import React, {Component} from 'react';
function getDisplayName(component) {
return component.displayName || component.name || 'Component';
}
export default (title)=>(WrappedComponent)=> class HOC extends Component {
// static displayName = `HOC(${getDisplayName(WrappedComponent)})`
render() {
return <div>
<div className="demo-header">
{title}
</div>
<WrappedComponent {...this.props}/>
</div>
}
}
基于属性代理的方式
import React, {Component} from 'react';
function getDisplayName(component) {
return component.displayName || component.name || 'Component';
}
export default (title)=>(WrappedComponent)=> class HOC extends Component {
// static displayName = `HOC(${getDisplayName(WrappedComponent)})`
render() {
const newProps = {
test:'hoc'
}
return <div>
<div className="demo-header">
{title}
</div>
<WrappedComponent {...this.props} {...newProps}/>
</div>
}
}
基于反向继承的方式
这种方式返回的React组件继承了被传入的组件,所以它能够访问到的区域、权限更多,相比属性代理方式,它更像打入组织内部,对其进行修改。具体的可以参考附录里提供的链接进行深入学习。
在这里我们引用高阶组件
import React, { Component } from 'react';
import widhtDemmoLoading from './demo-loading'
@widhtDemmoLoading(state => state.isLoading)
export default class Demo1 extends Component {
state = {
isLoading: true
};
componentDidMount(){
let _this=this
setTimeout(function(){
_this.setState({
isLoading: false
});
}, 3000);
}
render() {
console.log(this.props);
return (
<div>
我是一个正常普通组件
</div>
);
}
}
高阶组件写法
import React, {Component} from 'react';
export default (isCheck)=>(WrappedComponent)=> class extends WrappedComponent {
render() {
console.log(this.state);
return <div>
<div className="demo-header">
plus首页
</div>
{
isCheck(this.state) ? '加载中。。。' : '加载完成'
}
</div>
}
}
组合多个高阶组件
上面讲的,我们为组件增强了一个功能,加入需要同时增强多个功能呢。例如,我们需要给组件一个标题,同时又需要在页面为加载的时候显示一个loading
import React, { Component } from 'react';
import widthDemo1 from './demo-1';
import widhtDemmoLoading from './demo-loading'
@widthDemo1('我是普通组件的标题-高阶组件demo1122')
@widhtDemmoLoading(state => state.isLoading)
export default class Demo1 extends Component {}
使用compose可以简化上述过程,也能体现函数式编程的思想。
import React, { Component } from 'react';
import {compose} from 'redux'
import widthDemo1 from './demo-1';
import widhtDemmoLoading from './demo-loading'
const enhance=compose(widthDemo1('我是普通组件的标题-高阶组件demo1122'),widhtDemmoLoading(state => state.isLoading))
@enhance
export default class Demo1 extends Component {}
这里借用的是redux的compose 方法。
还可以直接引用这个方法
const compose= function (...funcs) {
if (funcs.length === 0) {
return arg => arg
}
if (funcs.length === 1) {
return funcs[0]
}
return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
高阶组件实战
总结
高阶组件最大的好处就是解耦和灵活性,在react的开发中还是很有用的。
当然这不可能是高阶组件的全部用法。掌握了它的一些技巧,还有一些限制,你可以结合你的应用场景,发散思维,尝试一些不同的用法。