目录
一 使用步骤
二 显示鼠标坐标
三 鼠标随图片移动
四 设置displayName
五 传递props
高阶组件HOC: Higher-Order Component,是一个函数,接收要包装的组件,返回增强后的组件
目的:实现状态逻辑复用
高阶组件就相当于手机壳, 采用包装(装饰)模式
一 使用步骤
1 创建一个函数,名称约定以with开头
2 指定函数的参数,参数以大写字母开头(作为要渲染的组件)
3 在函数内部创建一个类组件,提供复用的状态逻辑代码,并返回
4 渲染参数组件,同时将状态通过props传递给参数组件
5 调用该高阶组件,传入要增强的组件,通过返回值拿到增强后的组件,并将其渲染到页面中
二 显示鼠标坐标
import React from "react";
import ReactDOM from "react-dom";
// 1 创建一个函数,名称约定以with开头
// 2 指定函数的参数,参数以大写字母开头(作为要渲染的组件)
function withMouse(WrappedComponent) {
// 3 在函数内部创建一个类组件,提供复用的状态逻辑代码,并返回
class Mouse extends React.Component {
//鼠标状态
state = {
x: 0,
y: 0
}
//处理状态的逻辑代码
handleMouseMove = e => {
this.setState({
x: e.clientX,
y: e.clientY
})
}
//监听鼠标移动事件
componentDidMount() {
window.addEventListener("mousemove", this.handleMouseMove)
}
//解绑事件
componentWillUnmount() {
window.removeEventListener('mousemove', this.handleMouseMove)
}
render() {
//4 渲染参数组件,同时将状态通过props传递给参数组件
return <WrappedComponent {...this.state}/>
}
}
return Mouse;
}
const Position = props => (
<p>
鼠标当前位置:(x:{props.x},y:{props.y})
</p>
)
//调用该高阶组件,传入要增强的组件,通过返回值拿到增强后的组件,并将其渲染到页面中
const MousePosition = withMouse(Position)
class App extends React.Component {
render() {
return (
<div>
{/*渲染增强后的组件*/}
<MousePosition/>
</div>)
}
}
ReactDOM.render(<App/>, document.getElementById("root"));
效果

三 鼠标随图片移动
加入鼠标随图片移动的功能
import imgage from "./images/cat.jpg"
const Cat = props => (
<img src={imgage} alt='猫' style={{
position: 'absolute',
// 为了让鼠标在图片的中间,top减掉了图片的一半高度,left减掉了图片一半的宽度
top: props.y - 180,
left: props.x - 180
}}/>
)
//调用该高阶组件,传入要增强的组件,通过返回值拿到增强后的组件,并将其渲染到页面中
const MousePosition1 = withMouse(Cat)
完整代码
import React from "react";
import ReactDOM from "react-dom";
import imgage from "./images/cat.jpg"
// 1 创建一个函数,名称约定以with开头
// 2 指定函数的参数,参数以大写字母开头(作为要渲染的组件)
function withMouse(WrappedComponent) {
// 3 在函数内部创建一个类组件,提供复用的状态逻辑代码,并返回
class Mouse extends React.Component {
//鼠标状态
state = {
x: 0,
y: 0
}
//处理状态的逻辑代码
handleMouseMove = e => {
this.setState({
x: e.clientX,
y: e.clientY
})
}
//监听鼠标移动事件
componentDidMount() {
window.addEventListener("mousemove", this.handleMouseMove)
}
//解绑事件
componentWillUnmount() {
window.removeEventListener('mousemove', this.handleMouseMove)
}
render() {
//4 渲染参数组件,同时将状态通过props传递给参数组件
return <WrappedComponent {...this.state}/>
}
}
return Mouse;
}
const Cat = props => (
<img src={imgage} alt='猫' style={{
position: 'absolute',
// 为了让鼠标在图片的中间,top减掉了图片的一半高度,left减掉了图片一半的宽度
top: props.y - 125,
left: props.x - 100
}}/>
)
//调用该高阶组件,传入要增强的组件,通过返回值拿到增强后的组件,并将其渲染到页面中
const MousePosition1 = withMouse(Cat)
const Position = props => (
<p>
鼠标当前位置:(x:{props.x},y:{props.y})
</p>
)
//调用该高阶组件,传入要增强的组件,通过返回值拿到增强后的组件,并将其渲染到页面中
const MousePosition2 = withMouse(Position)
class App extends React.Component {
render() {
return (
<div>
{/*渲染增强后的组件*/}
<MousePosition1/>
<MousePosition2/>
</div>)
}
}
ReactDOM.render(<App/>, document.getElementById("root"));
四 设置displayName
默认情况下,react使用组件名称作为displayName
使用高阶组件存在的问题: 得到的两个组件名称相同

解决办法: 设置displayName → 用于调试时区分不同的组件

效果
完整代码
import React from "react";
import ReactDOM from "react-dom";
import imgage from "./images/cat.jpg"
// 1 创建一个函数,名称约定以with开头
// 2 指定函数的参数,参数以大写字母开头(作为要渲染的组件)
function withMouse(WrappedComponent) {
// 3 在函数内部创建一个类组件,提供复用的状态逻辑代码,并返回
class Mouse extends React.Component {
//鼠标状态
state = {
x: 0,
y: 0
}
//处理状态的逻辑代码
handleMouseMove = e => {
this.setState({
x: e.clientX,
y: e.clientY
})
}
//监听鼠标移动事件
componentDidMount() {
window.addEventListener("mousemove", this.handleMouseMove)
}
//解绑事件
componentWillUnmount() {
window.removeEventListener('mousemove', this.handleMouseMove)
}
render() {
//4 渲染参数组件,同时将状态通过props传递给参数组件
return <WrappedComponent {...this.state}/>
}
}
//设置displayName
Mouse.displayName = `withMouse${getDisplayName(WrappedComponent)}`
return Mouse;
}
//displayName
function getDisplayName(WrappedComponent) {
return WrappedComponent.displayName || WrappedComponent.name || 'Component'
}
const Cat = props => (
<img src={imgage} alt='猫' style={{
position: 'absolute',
// 为了让鼠标在图片的中间,top减掉了图片的一半高度,left减掉了图片一半的宽度
top: props.y - 125,
left: props.x - 100
}}/>
)
//调用该高阶组件,传入要增强的组件,通过返回值拿到增强后的组件,并将其渲染到页面中
const MousePosition1 = withMouse(Cat)
const Position = props => (
<p>
鼠标当前位置:(x:{props.x},y:{props.y})
</p>
)
//调用该高阶组件,传入要增强的组件,通过返回值拿到增强后的组件,并将其渲染到页面中
const MousePosition2 = withMouse(Position)
class App extends React.Component {
render() {
return (
<div>
{/*渲染增强后的组件*/}
<MousePosition1/>
<MousePosition2/>
</div>)
}
}
ReactDOM.render(<App/>, document.getElementById("root"));
五 传递props
问题:
添加了一个属性, 打印了props

属性没显示在props里
原因:props传递丢失
解决办法:

效果

完整代码
import React from "react";
import ReactDOM from "react-dom";
// 1 创建一个函数,名称约定以with开头
// 2 指定函数的参数,参数以大写字母开头(作为要渲染的组件)
function withMouse(WrappedComponent) {
// 3 在函数内部创建一个类组件,提供复用的状态逻辑代码,并返回
class Mouse extends React.Component {
//鼠标状态
state = {
x: 0,
y: 0
}
//处理状态的逻辑代码
handleMouseMove = e => {
this.setState({
x: e.clientX,
y: e.clientY
})
}
//监听鼠标移动事件
componentDidMount() {
window.addEventListener("mousemove", this.handleMouseMove)
}
//解绑事件
componentWillUnmount() {
window.removeEventListener('mousemove', this.handleMouseMove)
}
render() {
//4 渲染参数组件,同时将状态通过props传递给参数组件
return <WrappedComponent {...this.state}{...this.props}/>
}
}
return Mouse;
}
const Position = props => {
console.log(props)
return (
<p>
鼠标当前位置:(x:{props.x},y:{props.y})
</p>
)
}
//调用该高阶组件,传入要增强的组件,通过返回值拿到增强后的组件,并将其渲染到页面中
const MousePosition = withMouse(Position)
class App extends React.Component {
render() {
return (
<div>
{/*渲染增强后的组件*/}
<MousePosition a="1"/>
</div>)
}
}
ReactDOM.render(<App/>, document.getElementById("root"));