前言
不学不知道,一学吓一跳。这react跟vue相比,真是太能融合了。就拿这个高阶组件来说,里面融合了函数式组件,类组件,兄弟组件的状态提升,父子组件传值。还用到了函数柯里化这个思想,真是太牛X了,下面我们就一步一步来学习高阶组件的使用.
- 下面以一个demo来使用高阶组件完成:移动鼠标,图案跟着鼠标进行移动,并且在页面实时显示移动坐标
高阶组件的基本使用步骤
创建一个函数,名称预定以width开头
function widthMouse() {
}
指定函数的参数,参数以大写字母开头,作为要渲染的组件
function widthMouse(WrapCopmonent) {
}
在函数内部创建一个类组件,提供复用的状态逻辑代码,并返回
function widthMouse(WrapComponent) {
class Mouse extends React.Component {
}
return Mouse
}
提供复用的状态逻辑代码
- 状态:鼠标移动的坐标
- 逻辑: 根据鼠标的移动,对移动的坐标进行实时的更新
- 优化:在页面销毁时,将事件进行销毁
function widthMouse(WrapComponent) {
class Mouse extends React.Component {
state = {
x: '',
y: ''
}
handleMove = (e) => {
this.setState({
x: e.clientX,
y: e.clientY
})
}
componentDidMount() {
window.addEventListener('mousemove', this.handleMove)
}
componentWillUnmount() {
window.addEventListener('mousemove', this.handleMove)
}
}
return Mouse
}
在该组件中,渲染参数组件,同时将状态通过props传给参数组件
function widthMouse(WrapComponent) {
class Mouse extends React.Component {
state = {
x: '',
y: ''
}
handleMove = (e) => {
this.setState({
x: e.clientX,
y: e.clientY
})
}
componentDidMount() {
window.addEventListener('mousemove', this.handleMove)
}
componentWillUnmount() {
window.addEventListener('mousemove', this.handleMove)
}
render() {
return (
<div>
<WrapComponent {...this.state} />
</div>
)
}
}
return Mouse
}
调用该高阶组件,传入要增强的组件,通过返回值拿到增强后的组件并将其渲染到页面
// 测试高阶组件- 实现实时显示鼠标移动坐标
import img from './favicon.ico'
const Position = (props) => {
return (
<div>
x坐标 {props.x}
<br />
y坐标 {props.y}
</div>
)
}
const MousePosition = widthMouse(Position)
// 测试高阶组件- 实现图片随鼠标移动
const Logo = (props) => {
return (
<img src={img} style={{
position: 'absolute',
top: props.y,
left: props.x
}} />
)
}
const MouseLogo = widthMouse(Logo)
class App extends React.Component {
render() {
return (
<div>
<h1>高阶组件</h1>
<MousePosition />
<MouseLogo />
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'))
使用react调试工具,你会发现,由于Position和Logo两个组件都是通过高阶组件widthMouse来包装的,所以名字都一样,那我们可以通过displayName来设置组件名
Mouse.displayName = `widthMouse${getDisplayName(WrapComponent)}`
function getDisplayName(WrapComponent) {
return WrapComponent.displayName || WrapComponent.name || 'Component'
}
props传递
- 由于我们只是在接收高阶函数传来的值,那如果我想给高阶函数传递值,该怎么办呢
class App extends React.Component {
render() {
return (
<div>
<h1>高阶组件</h1>
<MousePosition a="props传递"/>
<MouseLogo />
</div>
)
}
}
- 首先他是传递了,是传递到函数内部创建一个类组件Mouse里了,但是在渲染参数组件的时候,没有=继续往下传,那我们在渲染参数组件的时候,给他传递进去就ok了
<WrapComponent {...this.state} {...this.props} />
所有代码
import img from './favicon.ico'
function widthMouse(WrapComponent) {
class Mouse extends React.Component {
state = {
x: '',
y: ''
}
handleMove = (e) => {
this.setState({
x: e.clientX,
y: e.clientY
})
}
componentDidMount() {
window.addEventListener('mousemove', this.handleMove)
}
componentWillUnmount() {
window.addEventListener('mousemove', this.handleMove)
}
render() {
return (
<div>
<WrapComponent {...this.state} {...this.props} />
</div>
)
}
}
Mouse.displayName = `widthMouse${getDisplayName(WrapComponent)}`
return Mouse
}
function getDisplayName(WrapComponent) {
return WrapComponent.displayName || WrapComponent.name || 'Component'
}
// 测试高阶组件- 实现实时显示鼠标移动坐标
const Position = (props) => {
return (
<div>
x坐标 {props.x}
<br />
y坐标 {props.y}
</div>
)
}
// 测试高阶组件- 实现图片随鼠标移动
const Logo = (props) => {
return (
<img src={img} style={{
position: 'absolute',
top: props.y,
left: props.x
}} />
)
}
const MouseLogo = widthMouse(Logo)
const MousePosition = widthMouse(Position)
class Appp extends React.Component {
render() {
return (
<div>
<h1>高阶组件</h1>
<MousePosition a="props传递" />
<MouseLogo />
</div>
)
}
}
ReactDOM.render(<Appp />, document.getElementById('root'))
总结
- 高阶组件是将函数式组件和类组件的一种融合,配得上这个名字
HOC - 函数柯里化的编程思想在高阶组件中的表现太优秀了
- 组件的传值是基础,在这基础之上的传值的再次融合,写的太有意思了