高阶组件(HighOrderComponent)是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而形成的设计模式。
具体来说,高阶组件是一个函数,能够接受一个组件并返回一个新的组件,通过高阶函数可以帮助我们实现某些逻辑的复用。通过一个例子学习一下HOC的使用,例如目前项目中有下面两个Counter:
- ClickCounter:通过点击按钮触发计数
- HoverCounter:鼠标移过时触发计数
//ClickCounter
import React, { Component } from "react";
class ClickCounter extends Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
incrementCount = () => {
this.setState(prevState => {
return { count: prevState.count + 1 };
});
};
render() {
return (
<div>
<button onClick={this.incrementCount}>
clicked {this.state.count} times
</button>
</div>
);
}
}
export default ClickCounter;
//HoverCounter
import React, { Component } from "react";
class HoverCounter extends Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
incrementCount = () => {
this.setState(prevState => {
return { count: prevState.count + 1 };
});
};
render() {
return (
<div>
<h3 onMouseOver={this.incrementCount}>
Hover {this.state.count} times
</h3>
</div>
);
}
}
export default HoverCounter;
两个Counter有一部终共同逻辑:
constructor(props) {
super(props)
this.state = {
count: 0
}
}
incrementCount = () => {
this.setState(prevState => {
return { count: prevState.count + 1 }
})
}
改造为HOC
现在我们想通过HOC复用两个Counter共同逻辑。再回顾一下HOC的本质:接受一个组件并返回一个新的组件
- 高阶组件:
higherOrderComponent
- 接受的组件 :
OriginalComponent
- 新组件 :
NewComponent
根据上述原则实现HOC如下:
//highOrderComponent
import React from 'react'
const higherOrderComponent = OriginalComponent => {
class NewComponent extends React.Component {
constructor(props) {
super(props)
this.state = {
count: 0
}
}
incrementCount = () => {
this.setState(prevState => {
return { count: prevState.count + 1 }
})
}
render() {
return <OriginalComponent count={this.state.count} incrementCount={this.incrementCount}/>
}
}
return NewComponent
}
export default higherOrderComponent
HOC代理了共同逻辑,OriginalComponent无需再重复实现。如果用OOP的设计模式看,这其实是一个代理模式
使用HOC替换OriginalComponent
在原组件的定义处将export组件替换为HOC
//ClickCounter
import React, { Component } from 'react'
import higherOrderComponent from './Counter'
class ClickCounter extends Component {
render() {
return (
<div>
<button onClick={this.props.incrementCount}>clicked {this.props.count} times</button>
</div>
)
}
}
export default higherOrderComponent(ClickCounter)
//HoverCounter
import React, { Component } from 'react'
import higherOrderComponent from './Counter'
class HoverCounter extends Component {
render() {
return (
<div>
<h3 onMouseOver={this.props.incrementCount}>Hover {this.props.count} times</h3>
</div>
)
}
}
export default higherOrderComponent(HoverCounter)
HOC的替换不会影响到原组件的使用方。