基本概念
在 JavaScript 中,高阶函数是以函数为参数,并且返回值也是函数的函数。类似地,高阶组件(简称 HOC)接收 React 组件作为参数,并且返回一个新的 React 组件。高阶组件本质上也是一个函数,并不是一个组件。高阶组件的函数形式如下:
const EnhancedComponent = higherOrderComponent(WrappedComponent);
我们先通过一个简单的例子看一下高阶组件是如何进行逻辑复用的。现在有一个组件 MyComponent,需要从 LocalStorage 中获取数据,然后渲染到界面。一般情况下,我们可以这样实现:
import React, { Component } from 'react'
class MyComponent extends Component {
componentWillMount() {
let data = localStorage.getItem('data');
this.setState({data});
}
render() {
return <div>{this.state.data}</div>
}
}
代码很简单,但当其他组件也需要从 LocalStorage 中获取同样的数据展示出来时,每个组件都需要重写一次 componentWillMount 中的代码,这显然是很冗余的。下面让我们来看看使用高阶组件改写这部分代码。
import React, { Component } from 'react'
function withPersistentData(WrappedComponent) {
return class extends Component {
componentWillMount() {
let data = localStorage.getItem('data');
this.setState({data});
}
render() {
// 通过 {...this.props} 把传递给当前组件的属性继续传递给被包装的组件
return <WrappedComponent data={this.state.data} {...this.props} />
}
}
}
class MyComponent extends Component {
render() {
return <div>{this.props.data}</div>
}
}
const MyComponentWithPersistentData = withPersistentData(MyComponent)
withPersistentData 就是一个高阶组件,它返回一个新的组件,在新组件的 componentWillMount 中统一处理从 LocalStorage 中获取数据的逻辑,然后将获取到的数据通过 props 传递给被包装的组件 WrappedComponent,这样在 WrappedComponent 中就可以直接使用 this.props.data 获取需要展示的数据。当有其他的组件也需要这段逻辑时,继续使用 withPersistentData 这个高阶组件包装这些组件。
通过这个例子可以看出高阶组件的主要功能是封装并分离组件的通用逻辑,让通用逻辑在组件间更好地被复用。高阶组件的这种实现方式本质上是装饰者设计模式。