高阶组件是一个复用组件逻辑的高级用法,他不是react API的部分,而是react自然生态衍生出来的一种模式。
概述
具体的说,HOC(higher-order component)是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件。
const EnhancedComponent = higherOrderComponent(WrappedComponent);
export default EnhancedComponent;
作用
高阶组件的主要作用是解决交叉问题,如多个功能极其相似的组件可用高阶组件达到复用的目的。
约定
- 传递无关的props至包裹组件
render() {
const { extraProp, ...passThroughProps } = this.props;
const injectedProp = someStateOrInstanceMethod;
// Pass props to wrapped component
return (
<WrappedComponent
injectedProp={injectedProp}
{...passThroughProps}
/>
);
}
- 最大化可组合性
有时候HOC接收多个参数,且HOC嵌套HOC如:
// React Redux 的 `connect` 函数
const ConnectedComment = connect(commentSelector, commentActions)(CommentList);
这样看起来就很迷惑,可以使用lodash
或者ramda
的compose
来解决
const enhance = compose(
withRouter,
connect(commentSelector)
)
- 包装显示名称以便轻松调试
HOC 创建的容器组件会与任何其他组件一样,会显示在 React Developer Tools
中。为了方便调试,请选择一个显示名称,以表明它是 HOC
的产物
最常见的方式是用 HOC 包住被包装组件的显示名称。比如高阶组件名为 withSubscription
,并且被包装组件的显示名称为 CommentList
,显示名称应该为 WithSubscription(CommentList):
function withSubscription(WrappedComponent) {
class WithSubscription extends React.Component {/* ... */}
WithSubscription.displayName = `WithSubscription(${getDisplayName(WrappedComponent)})`;
return WithSubscription;
}
function getDisplayName(WrappedComponent) {
return WrappedComponent.displayName || WrappedComponent.name || 'Component';
}
注意
- 高阶组件是一个没有副作用的纯函数,所以不要修改原组件,使用组合的形式。
function logProps(InputComponent) {
InputComponent.prototype.componentWillReceiveProps = function(nextProps) {
console.log('Current props: ', this.props);
console.log('Next props: ', nextProps);
};
// The fact that we're returning the original input is a hint that it has
// been mutated.
return InputComponent;
}
不要在render函数中使用高阶函数
必须将静态方法做拷贝
当使用高阶组件包装组件,原始组件被容器组件包裹,也就意味着新组件会丢失原始组件的所有静态方法。
解决这个问题的方法就是,将原始组件的所有静态方法全部拷贝给新组件:
function enhance(WrappedComponent) { class Enhance extends React.Component {/*...*/} // 必须得知道要拷贝的方法 :( Enhance.staticMethod = WrappedComponent.staticMethod; return Enhance; }
这样做,就需要你清楚的知道都有哪些静态方法需要拷贝。你可以使用hoist-non-react-statics来帮你自动处理,它会自动拷贝所有非React的静态方法:
注意
- Refs属性不能传递
参考
- The react official website, ✨ HOC