一、HOC高阶组件
1.介绍
高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件
1 | const NewComponent = higherOrderComponent(OldComponent) |
构建了一个新的组件类 NewComponent,然后把传进入去的 WrappedComponent 渲染出来
1 | import React, { Component } from 'react' |
2.使用
- 普通函数包裹
- 装饰器
1
2
3
4
5@decorator
class A {}
// 等同于
class A {}
A = decorator(A) || A;
3.分类
代理方式
- 操纵prop:在 render 函数中, this.props 包含新组件接收到的所有 prop,最简单的方式当然是把 this.props 原封不动地传递给被包裹组件,当然,高阶组件也可以增减、删除、修改传递 给包裹组件的 props列表
1
2
3
4
5
6const addNewProps = (WrappedComponent, newProps) => { return class WrappingComponent extends React.Component {
render() {
return <WrappedComponent {... this.props} {... newProps} />
}
}
}访问ref:能够获得被包裹组件的直接应用 ref,然后就可以根据 ref直接操纵被包裹组件的实例
1
2
3
4
5
6
7
8
9
10
11
12const refsHOC = (WrappedComponent) => {
return class HOCComponent extends React . Component {
constructor () {
super (... arguments) ;
this.linkRef = this.linkRef.bind(this);
linkRef(wrappedinstance} { this._root = wrappedinstance ;
}
render(} {
const props= {. .. this .props , ref : this.linkRef} ; return <WrappedComponent {.. .props}/>;
}
};
};抽取状态:类似于connect
1
2
3
4
5
6
7
8
9
10
11const doNothing = () => ({}) ;
function connect(mapStateToProps=doNothing, mapDispatchToProps=doNothing) { return function(WrappedComponent) {
class HOCComponent extends React.Component {
//在这里定义HOCComponent的生命周期函数
};
HOCComponent.contextTypes = {
store: React.PropTypes.object
}
return HOCComponent;
};
}包装组件: JSX 中完全可以引人其他的元素,甚至可以 组合多个 React 组件,这样就会得到更加丰富多彩的行为
1
2
3
4
5
6
7
8
9
10const styleHOC = (WrappedComponent, style) => {
return class HOCComponent extends React.Component {
render() { return (
<div style={style}>
<WrappedComponent {... this.props}/>
</div>
);
}
};
};
继承方式
1
2
3
4
5
6
7
8function removeUserProp(WrappedComponent) {
return class NewComponent extends WrappedComponent {
render() {
const {user, ... otherPropsl = this.props; this .props = otherProps;
return super.render();
}
};
}代理方式和继承方式最大的区别,是使用被包裹组件的方式
在代理方式下 WrappedComponent经历了一个完整的生命周期,但在继承方式下 super.render 只是一个生命周期中的一个函数而已;在代理方式下产生的新组件和参数组件是两个不同的组件,一次渲染,两个组件都要经历各自的生命周期,在继承方式下两者合二为一,只有一个生命周期- 操纵prop:可以使用React.cloneElemen,不建议,直接使用代理方式即可
- 操纵生命周期函数:因为继承方式的高阶函数返回的新组件继承了参数组件,所以可以重新定义任何一个React组件的生命周期函数
二、实际应用
1 | import React, { Component } from 'react'; |
在需要使用的组件进行绑定
1 | import ExcelExport from '../ExcelExport'; |
三、约定
将不相关的props属性传递给包裹组件。高阶组件给组件添加新特性。他们不应该大幅修改原组件的接口(译者注:应该就是props属性)。预期,从高阶组件返回的组件应该与原包裹的组件具有类似的接口。
最大化使用组合。
例子:connect 是一个返回高阶组件的高阶函数
1
2// React Redux's `connect`
const ConnectedComment = connect(commentSelector, commentActions)(Comment);1
2
3
4
5// connect是一个返回函数的函数(译者注:就是个高阶函数)
const enhance = connect(commentListSelector, commentListActions);
// 返回的函数就是一个高阶组件,该高阶组件返回一个与Redux store
// 关联起来的新组件
const ConnectedComment = enhance(CommentList);包装显示名字以便于调试
四、注意事项
- 不要在render函数中使用高阶组件
- 必须将静态方法做拷贝
- Refs属性不能传递
五、拓展——以函数为子组件
高阶组件缺点:能不能把一个高阶组件作用于某个组件X,要先看一下这个组件X是不是能够接受高阶组件传过来的props
举例:
1 | const loggedinUser = ’ mock user ’; |
使用:
1 | <AddUserProp> |
以后想到了实际应用再补充