高阶组件的定义
接受React组件作为输入,输出一个新的React组件。
概念源自于高阶函数,将函数作为参数,或者输出一个函数,如map,reduce,sort。
用haskell的函数签名来表示:
hocFactory:: W: React.component => E: React.component
使用场景
可以用来对组件进行二次加工和抽象,比如:对Input组件进行样式改动、添加新的props属性;某些可以复用的逻辑抽象后再注入组件。
所以 HOC 的作用大概有以下几点:
- 代码复用和逻辑抽象
- 对 state 和 props 进行抽象和操作
- Render 劫持
如何实现
- 属性代理(props proxy):高阶组件通过被包裹的React组件来操作props,从而能够实现控制props、引用refs、抽象state。
1.1 控制props
import React, { Component, Fragment } from 'react';
const MyContainer = WrappedComponent =>
class extends Component {
render() {
const newProps = {
text: 'newText',
};
return (
<>
<span>通过 props proxy 封装HOC</span>
<WrappedComponent {...this.props} {...newProps} />
</>
);
}
};
从这里可以看到,在render中返回来传入WrappedComponent 的React组件,这样我们就可以通过HOC在props中传递属性、添加组件及样式等等。
使用也是非常简单:
import React, { Component } from 'react';
import MyContainer from './MyContainer.jsx';
class App extends Component {
...
}
export default MyContainer(App);
当然也可以使用装饰器@decorator:”接收一个类作为参数,返回一个新的内部类“,与HOC的定义如出一辙,十分契合。
import React, { Component } from 'react';
import MyContainer from './MyContainer.jsx';
@MyContainer
class App extends Component {
...
}
export default App;
1.2 通过refs使用引用
import React, { Component } from 'react';
const RefsHOC = WrappedComponent =>
class extends Component {
proc(wrappedComponentInstance) {
wrappedComponentInstance.refresh();
}
render() {
const props = Object.assign({}, this.props, { ref: this.proc.bind(this) });
return <WrappedComponent {...props} />;
}
};
export default RefsHOC;
render() 时会执行 ref 回调,即proc方法,该方法可以获取 WrappedComponent 的实例,其中包含组件的 props,方法,context等。我们也可以在 proc 中进行一些操作,如控制组件刷新等。
1.3 抽象state
我们可以通过向 WarppedComponent 提供 props 和 回调函数抽象state,将原组件抽象成展示型组件,隔离内部state。
import React, { Component } from 'react';
const MyContainer = WrappedComponent =>
class extends Component {
constructor(props) {
super(props);
this.state = {
name: '',
};
}
onHandleChange = e => {
const val = e.target.value;
this.setState({
name: val,
});
};
render() {
const newProps = {
name: {
value: this.state.name,
onChange: this.onHandleChange,
},
};
return <WrappedComponent {...this.props} {...newProps} />;
}
};
我们将 input 组件中 name props 的 onChange方法提取到了高阶组件中,这样就有效的抽象了同样的state操作。
import React, { Component } from 'react';
import MyContainer from './MyContainer.jsx';
@MyContainer
class MyInput extends Component {
render() {
return <input type="text" {...this.props.name} />;
}
}
export default MyInput;
参考链接
深入React技术栈book.douban.com Javascript 中的装饰器aotu.io