高阶组件的定义
接受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.comJavascript 中的装饰器aotu.io