定义
高阶组件:High Oder Component,入参为组件,出参也为组件。且不会改变参数组件,所以该函数是个纯函数,不会有副作用。
高阶组件可以对参数组件做统一处理逻辑,常见场景如:权限控制、属性代理
作用
- 功能代码的抽象,提升复用性
- 控制组件的渲染流程
- 检测组件性能
属性代理
方式一:props
函数组件
function HOC(WrappedComponent) {
const newProps = { type:'HOC' }
return props => <WrappedComponent {...props} {...newProps}/>
}
类组件
function HOC(WrappedComponent) {
return class extend React.Component {
render() {
const newProps = { type: 'HOC' }
return <WrappedComponent {...this.props} {...newProps}/>
}
}
}
方式二:抽象state
模拟给参数组件中添加state
function HOC(WrappedComponent){
return class extends React.Component{
constructor(props){
super(props)
this.state = {name:'田本初'}
this.onChange = this.onChange.bind(this)
}
onChange(e){
this.setState({name:e.target.value})
}
render() {
const newProps = {
name: this.state.name,
onChange: this.onChange
}
return <WrappedComponent {...this.props}{...newProps}/>
}
}
}
方式三: 控制渲染逻辑
function HOC(WrappedComponent){
if(props.type === '1'){
return <div className="style1"><WrappedComponent/></div>
}else if(props.type === '2'){
return <div className="style2"><WrappedComponent/></div>
}else{
return <div>xxx</div>
}
}
反向继承
通过直接继承参数组件,创建一个新组件并返回。
function HOC(WrappedComponent){
const didMount = WrappedComponent.prototype.componentDidMount
return class extend WrappedComponent{
// 对参数组件的生命周期进行修改
async componentDidMount(){
if(didMount){
await didMount.apply(this)
// ....其他操作
}
}
render(){
return super.render()
}
}
}
这种方式更加灵活,可以任意进行渲染逻辑的控制以及修改state。
function HOC(WrappedComponent){
return class extend WrappedComponent{
render(){
const tree = super.render()
const newProps = {}
if(tree && tree.type === 'input'){
newProps.value = '田本初'
}
const props = { ...tree.props,...newProps }
const newTree = React.cloneElement(tree,props,tree.props.children)
return newTree
}
}
}
计算组件渲染耗时
function withTime(WrappedComponent){
return class extend WrappedComponent{
constructor(props){
super(props)
start,
end
}
componentWillMount(){
if(super.somponentWillMount){
super.componentWillMount()
}
start = +new Date()
}
componentDidMount(){
if(super.componentDidMount){
super.componentDidMount()
}
end = +new Date()
console.log(`渲染耗时${end - start}ms`)
}
render(){
return super.render()
}
}
}
属性代理与反向继承对比
二者同样对参数组件进行处理,但是反向继承比属性代理更加强大,不同于属性代理只能操作组件外部,反向继承相当于复制了一个参数组件,并进行修改,更加灵活。