趣味理解:一个组件进了一个工厂,出来了就变成了带装备的组件,这个工厂就是高阶组件

  • 高阶组件是一个函数,接受一个组件作为参数,返回一个新的组件
  • 可作为装饰器使用

高阶组件有两种实现形式,属性代理和反向继承

  • 属性代理: 高阶组件通过被包裹的React组件来操作props,实现对原组件props的增删改查
  • 反向继承: 高阶组件继承于被包裹的React组件

先来说说属性代理

这是一个最简单的实现,也是最常见的一种声名高阶组件的方法

1
2
3
4
5
6
7
8
9
import React,{Component} from 'react';

const MyContainer = (WraooedComponent) => {
return class extends Component {
render(){
return <WrappedComponent {...this.props} />
}
}
}

属性代理–操作props
属性代理可以对原组件的props进行增删改查,通常是查找和增加,删除和修改的话,需要考虑到不能破坏原组件

1
2
3
4
5
6
7
8
9
10
function ppHOC(WrappedComponent) {
return class PP extends React.Component {
render() {
const newProps = {
user: currentLoggedInUser
}
return <WrappedComponent {...this.props} {...newProps}/>
}
}
}

属性代理–通过refs访问组件实例
可以通过ref回调的形式来访问组件实例,进而调用组件相关方法和其他操作

1
2
3
4
5
6
7
8
9
10
11
12
13
//WrappedComponent初始渲染时候会调用ref回调,传入组件实例,在proc方法中,就可以调用组件方法
function refsHOC(WrappedComponent) {
return class RefsHOC extends React.Component {
proc(wrappedComponentInstance) {
wrappedComponentInstance.method()
}

render() {
const props = Object.assign({}, this.props, {ref: this.proc.bind(this)})
return <WrappedComponent {...props}/>
}
}
}

属性代理–提取state
可以通过传入props和回调函数把state提取出来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
function ppHOC(WrappedComponent) {
return class PP extends React.Component {
constructor(props) {
super(props)
this.state = {
name: ''
}

this.onNameChange = this.onNameChange.bind(this)
}
onNameChange(event) {
this.setState({
name: event.target.value
})
}
render() {
const newProps = {
name: {
value: this.state.name,
onChange: this.onNameChange
}
}
return <WrappedComponent {...this.props} {...newProps}/>
}
}
}

//使用方式如下
@ppHOC
class Example extends React.Component {
render() {
//使用ppHOC装饰器之后,组件的props被添加了name属性,可以通过下面的方法,将value和onChange添加到input上面
//input会成为受控组件
return <input name="name" {...this.props.name}/>
}
}

属性代理–包裹父级容器
为了封装样式,布局等目的,可以将组件用一个容器包裹起来,再不影响组件内部的同时改变了组件的布局,样式等

1
2
3
4
5
6
7
8
9
10
11
function ppHOC(WrappedComponent) {
return class PP extends React.Component {
render() {
return (
<div style={{display: 'block'}}>
<WrappedComponent {...this.props}/>
</div>
)
}
}
}

继承反转
HOC继承了传入的组件,意味着可以访问到传入组件的state,props,生命周期和render方法,如果在HOC中定义了与传入组件同名方法,就必须手动通过super进行调用,通过完全操作传入组件的render方法返回的元素树,可以真正实现渲染劫持这种思想具有较强的入侵性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function ppHOC(WrappedComponent) {
return class ExampleEnhance extends WrappedComponent {
...
componentDidMount() {
super.componentDidMount();
}
componentWillUnmount() {
super.componentWillUnmount();
}
render() {
...
return super.render();
}
}
}

参考传送门1
参考传送门2
参考传送门3