react 高阶组件
高阶函数(Higher-order funciton)
简称:HOC,至少满足下面一个条件
- 接受一个或者多个函数作为输入
- 输出一个函数
const EnhancedComponent = highOrderComponent(WrappedComponent);
该函数接收一个组件WrappedComponent
作为参数,返回加工过的新组建EnhancedComponent
.
本质上是一个装饰者模式
基本模版
import React, { Component } from 'react';
export default (WrappedComponent) => {
return class EnhancedComponent extends Component {
// do something
render() {
return <WrappedComponent />;
}
}
}
通过对传入的原始组件WrappedComponent
,做一些你想要的操作(比如:操作props
,提取state
,给原始组件包裹其他元素),从而加工出想要的组件EnhancedComponent
.
把通用的逻辑放在高阶组件中,对组件实现一致的处理,从而实现代码的复用
遵循约定:
props
保持一致- 不鞥在函数式(无状态)组件上使用
ref
属性,因为他没有实例 - 不要以任何方式改变原始组件
WrappedComponent
- 透传不相关
props
属性给被包裹的组件WrappedComponent
- 不要在
render()
方法中使用高阶组件 - 使用
compose
组合高阶组件
注意:高阶组件可以传递所有的
props
,但是不能传递ref
如果想一个高阶组件添加refs
引用,那么ref
指向的是最外层容器组件实例的,而不是被包裹的组件,如果需要传递refs
的话,则使用React.forwardRef
如下:
function withLogging(WrappedComponent) {
class Enhance extends WrappedComponent {
componentWillReceiveProps() {
console.log('Current props', this.props);
console.log('Next props', nextProps);
}
render() {
const {forwardedRef, ...rest} = this.props;
// forwardedRef ref
return <WrappedComponent {...rest} ref={forwardedRef} />;
}
};
// React.forwardRef props ref
// ref React.forwardRef
function forwardRef(props, ref) {
return <Enhance {...props} forwardRef={ref} />
}
return React.forwardRef(forwardRef);
}
const EnhancedComponent = withLogging(SomeComponent);
使用场景
如:权限控制,日志记录,数据校验,异常处理,统计上报等…
举例,存在一个组件,需要从缓存中获取数据,然后渲染。
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>
}
}
高阶组件改写:
import React, { Component } from 'react'
function withPersistentData(WrappedComponent) {
return class extends Component {
componentWillMount() {
let data = localStorage.getItem('data');
this.setState({data});
}
render() {
// {...this.props} WrappedComponent
return <WrappedComponent data={this.state.data} {...this.props} />
}
}
}
class MyComponent2 extends Component {
render() {
return <div>{this.props.data}</div>
}
}
const MyComponentWithPersistentData = withPersistentData(MyComponent2)
比如组件渲染性能监控,如下:
class Home extends React.Component {
render() {
return (<h1>Hello World.</h1>);
}
}
function withTiming(WrappedComponent) {
return class extends WrappedComponent {
constructor(props) {
super(props);
this.start = 0;
this.end = 0;
}
componentWillMount() {
super.componentWillMount && super.componentWillMount();
this.start = Date.now();
}
componentDidMount() {
super.componentDidMount && super.componentDidMount();
this.end = Date.now();
console.log(`${WrappedComponent.name} ${this.end- this.start} ms`);
}
render() {
return super.render();
}
};
}