【前端框架】react框架 第四章 react组件进阶

1. 组件的props

  1. 组件是封闭的,要接收外部数据应该通过props来实现
  2. props的作用:接收传递给组件的数据
  3. 传递数据:给组件标签添加属性
  4. 接收数据:函数组件通过参数props接收数据,类组件通过this.props接收数据

函数组件接收外部数据:

import React from 'react'
import ReactDOM from 'react-dom'
// 2、接收数据
const App = props => {
    
    
    // props是一个对象
    return (
        <div>
            <h1>props:{
    
    props.name}</h1>
        </div>
    )
}

// 渲染组件 1、传递数据:传递了一个名字和一个数字。注意:“19”:为字符串,{19}:为number 19
ReactDOM.render(<App name="guili" age={
    
    19} />, document.getElementById('root'))

类组件接收外部数据:

import React from 'react'
import ReactDOM from 'react-dom'
// 2、接收数据
class App extends React.Component {
    
    
    render(){
    
    
        // props是一个对象
        return (
            <div>
                <h1>props:{
    
    this.props.age}</h1>
            </div>
        )
    }
}

// 渲染组件 1、传递数据:传递了一个名字和一个数字。注意:“19”:为字符串,{19}:为number 19
ReactDOM.render(<App name="guili" age={
    
    19} />, document.getElementById('root'))

特点

  1. 可以给组件传递任意类型的数据
  2. props只读对象,只能读取属性的值,无法修改对象
  3. 注意:使用类组件时,如果写了构造函数,应该将props传递给super(),否则,无法在构造函数中获取到props!

代码实现:
函数组件接收数据:

import React from 'react'
import ReactDOM from 'react-dom'
// 2、接收数据
const App = props=> {
    
    
        props.fn()//接收一个函数
        return (// props是一个对象
            <div>
                <h1>props:{
    
    this.props.age}</h1>
                {
    
    this.props.tag}//接收标签
            </div>
        )
    
}

// 渲染组件 1、传递数据:传递了一个名字和一个数字。注意:“19”:为字符串,{19}:为number 19
ReactDOM.render(<App 
    name="guili" //可以传递字符串
    age={
    
    19} //可以传递number
    colors={
    
    ['red','green','blue']}//可以传递数组
    fn={
    
    ()=>console.log('这是一个函数')}//可以传递函数
    tag={
    
    <p>这是一个p标签</p>}//可以传递标签
    />, document.getElementById('root'))

类组件接收数据:

import React from 'react'
import ReactDOM from 'react-dom'
// 2、接收数据
class App extends React.Component {
    
    
	//推荐使用props作为constructor的参数!!
    constructor(props) {
    
    
    //推荐将props传递给父类构造函数
        super(props)
    }
    render() {
    
    
        return <div>接收到的数据:{
    
    this.props.age}</div>
    }
  
}

// 渲染组件 1、传递数据:传递了一个名字和一个数字。注意:“19”:为字符串,{19}:为number 19
ReactDOM.render(<App 
    name="guili" //可以传递字符串
    age={
    
    19} //可以传递number
    colors={
    
    ['red','green','blue']}//可以传递数组
    fn={
    
    ()=>console.log('这是一个函数')}//可以传递函数
    tag={
    
    <p>这是一个p标签</p>}//可以传递标签
    />, document.getElementById('root'))

2. 组件通迅的三种方式

  1. 父组件–>子组件
  2. 子组件–>父组件
  3. 兄弟组件

父组件传递数据给子组件

  1. 父组件提供要传递的state数据
  2. 给子组件标签添加属性,值为state中的数据
  3. 子组件通过props接收父组件中传递的数据
// 父组件
class Parent extends React.Component {
    
    
    state = {
    
    lastName:'曾'}
    super(props)
    render() {
    
    
        return (
            <div>
                传递数据给子组件<Child name={
    
    this.state.lastName}></Child>
            </div>
        )
    }
  
}
// 子组件
const Child = () => {
    
    
    return (
        <div>
            <p>子组件,接收到父组件的数据:{
    
    props.name}</p>
        </div>
    )
}

代码实现:

import React from 'react'
import ReactDOM from 'react-dom'
// 父组件
class Parent extends React.Component {
    
    
    state = {
    
    
        lastName:'曾'
    }
    super(props)
    render() {
    
    
        return (
            <div className='parent'>
                父组件:
                <Child name={
    
    this.state.lastName}></Child>
            </div>
        )
    }
  
}
// 子组件
const Child = () => {
    
    
    return (
        <div className='child'>
            <p>子组件,接收到父组件的数据:{
    
    props.name}</p>
        </div>
    )
}

ReactDOM.render(<Parent />, document.getElementById('root'))

子组件传递数据组父组件

思路:利用回调函数,父组件提供回调,子组件调用,将要传递的数据作为回调函数的参数

  1. 父组件提供一个回调函数(用于接收数据)
  2. 将该函数作为属性的值,传递给子组件
  3. 子组件通过props调用回调函数
  4. 将子组件的数据作为参数传递给回调函数

注意:回调函数中this的指向问题

代码实现:

import React from 'react'
import ReactDOM from 'react-dom'

// 父组件
class Parent extends React.Component {
    
    
    // 提供回调函数,用来接收数据
    getChildMsg = data => {
    
    
        console.log('接收到子组件中传递过来的数据',data)
    }

    render() {
    
    
        return (
            <div className='parent'>
                <Child />
                传递数据给子组件<Child name={
    
    this.getChildMsg}></Child>
            </div>
        )
    }
  
}
// 子组件
class Child extends React.Component{
    
    
    state = {
    
    
        msg:'桂莉'
    }
    handleClick = () => {
    
    
        // 子组件调用父组件中传递过来的回调函数
        this.props.getMsg(this.state.msg)
    }
    render() {
    
    
        return (
            <div className='child'>
                子组件:{
    
    ' '}
                <button onClick={
    
    this.handleClick}>点我,给父组件传递数据</button>
            </div>
        )
    }
}

ReactDOM.render(<Parent />, document.getElementById('root'))


兄弟组件

  1. 共享状态提升到最近的公共父组件中,由公共父组件管理这个状态
  2. 思想:状态提升
  3. 公共父组件的职责:1. 提供操作共享状态方法
  4. 要通迅的子组件只需通过props接收状态或操作状态的方法

代码实现:

import React from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'

// 父组件
class Counter extends React.Component{
    
    
    // 提供共享状态
    state = {
    
    
        count:0
    }
    // 提供修改状态的方法
    onIncrement=(){
    
    
        this.setState({
    
    
            count:this.state.count+1
        })
    }
    render(){
    
    
        return(
            <div>
                <Child1 count={
    
    this.state.count}/>
                <Child2 onIncrement={
    
    this.onIncrement}/>
                
            </div>
        )
    }
}

const Child1 = props=>{
    
    
    return <h1>计数器:{
    
    props.count}</h1>
}

const Child2 = (props)=>{
    
    
    return <button onClick={
    
    ()=>props.onIncrement()}>+1</button>
}

ReactDOM.render(<Counter/>,document.getElementById('root'))


3. Context

作用:跨组件传递数据

Context使用步骤

  1. 调用React.createContext()创建Provider(提供数据)和 Consumer(消费数据)两个组件
const {
    
     Provider, Consumer } = React.createContext()
  1. 使用Provider组件作为父节点
<Provider>
	<div className='app'>
  		<Node />
	</div>
</Provider>
  1. 设置valu有属性,表示要传递的数据
<Provider value="pink">
  1. 调用Consumer组件接收数据
<Consumer>
{
    
    data => <span>我是子节点:{
    
    data}</span>}
</Consumer>

代码实现:

import React from 'react'
import ReactDOM from 'react-dom'

// 创建context得到两个组件
const {
    
     Provider, Consumer } = React.createContext()

class App extends React.Component{
    
    
    render() {
    
    
        return (
            <Provider value="pink">
                <div className='app'>
                    <Node />
                </div>
            </Provider>
        )
    }
}
// 子组件
const Node = props => {
    
    
    return (
        <div className='node'>
            <SubNode />
        </div>
    )
}

const SubNode = props => {
    
    
    return (
        <div className='subnode'>
            <Child/>
        </div>
    )
}

const Child = props => {
    
    
    return (
        <div className='child'>
            <Consumer>{
    
    data => <span>我是子节点:{
    
    data}</span>}</Consumer>
        </div>
    )
}

ReactDOM.render(<App />, document.getElementById('root'))

总结:

  1. 如果两个组件是远方亲戚(比如多层嵌套)可以使用Context实现组件通迅
  2. Context提供了两个组件:Provider和Consumer
  3. Provider组件:用来提供数据
  4. Consumer组件:用来消费数据

4. props深入

  1. children属性:表示组件标签的子节点。当组件标签有子节点时,props就会有该属性
  2. children属性与普通的props 一样,值可以是任意值(文本、React元素、组件、甚至是函数)

children为文本节点:

import React from 'react'
import ReactDOM from 'react-dom'

const App = props => {
    
    
    return (
        <div>
            <h1>组件标签的子节点</h1>
            {
    
    props.Children}
        </div>
    )
}

ReactDOM.render(<App>我是子节点</App>, document.getElementById('root'))

children为JSX或组件节点:

import React from 'react'
import ReactDOM from 'react-dom'

const Test =()=><button>我是button组件</button>
const App = props => {
    
    
    return (
        <div>
            <h1>组件标签的子节点</h1>
            {
    
    props.Children}
        </div>
    )
}

ReactDOM.render(<App>
    {
    
    /* <p>我是子节点,是一个p标签</p> */}
    <Test/>
</App>, document.getElementById('root'))

children为函数节点:

import React from 'react'
import ReactDOM from 'react-dom'

const App = props => {
    
    
    console.log(props)
    props.children()
    return (
        <div>
            <h1>组件标签的子节点</h1>
            {
    
    /* {props.Children} */}
        </div>
    )
}

ReactDOM.render(<App>
    {
    
    ()=>console.log('这是一个函数子节点')}
</App>, document.getElementById('root'))

props校验

使用步骤:

  1. 安装prop-types,在VScode终端输入命令:
yarn add prop-types

npm i props types
  1. 导入prop-types包
  1. 使用组件名.propTypes={}来给组件的props添加校验规则
  1. 校验规则通过PropTypes对象来指定
// 导入prop-types包
import PropTypes form 'prop-types'

const App = props => {
    
    
    return <h1>{
    
    props.colors}</h1>
}

// 添加 props校验
App.prototypes = {
    
    
    // 约定colors属性为array类型
    // 如果类型不对,则报出明确错误,便于分析错误原因
    colors:PropTypes.array
}

代码实现:

import React from 'react'
import ReactDOM from 'react-dom'

// 导入prop-types包
import PropTypes form 'prop-types'

const App = props => {
    
    
    const arr = props.colors
    const lis = arr.map((item, index) => <li key={
    
    index}>{
    
    item}</li>)
    return <ul>{
    
    lis}</ul>
}

// 添加 props校验
App.prototypes = {
    
    
    colors:PropTypes.array
}

ReactDOM.render(<App colors={
    
    ['red','blue']}/>,
document.getElementById('root')
)

约束规则:

  1. 常见类型:array, bool, number, object, string。可以在这查看其他PropTypes
  2. React元素类型:element
  3. 必填项:inPequired
  4. 特定结构的对象:shape({})
a:PropTypes.number,//常见类型
    fn:PropTypes.func.isRequired,//必选
    tag:PropTypes.element,
    filter:PropTypes.shape({
    
    //特定结构的对象
        area:PropTypes.string,
        price:PropTypes.number
    })

代码实现:

import React from 'react'
import ReactDOM from 'react-dom'

// 导入prop-types包
import PropTypes form 'prop-types'

const App = props => {
    
    

    return (
        <div>
        <h1>props校验:</h1>
        </div>
    )
}

// 添加 props校验
// 属性a的类型                   数值(number)
// 属性fn的类型                  函数(func)并且为必填项
// 属性tag的类型                 React元素(element)
// 属性filter的类型              对象({area:'上海',price:1999})
App.prototypes = {
    
    
    // 如果类型不对,则报出明确错误,便于分析错误原因
    a:PropTypes.number,
    fn:PropTypes.func.isRequired,
    tag:PropTypes.element,
    filter:PropTypes.shape({
    
    
        area:PropTypes.string,
        price:PropTypes.number
    })

}

ReactDOM.render(<App fn=()=>{
    
    } />,document.getElementById('root')
)

props的默认值

  1. 场景:分布组件–>每页显示条数
  2. 作用:给props设置默认值,在未传入props时生效
import React from 'react'
import ReactDOM from 'react-dom'

const App =props=>{
    
    
    console.log(props)
    return(
        <div>
            <h1>在此处展示props的默认值:{
    
    props.pageSize}</h1>
        </div>
    )
}
// 设置props默认值
App.defaultProps={
    
    
    pageSize:20
}
// 这里传入的权限高于设置的默认值
ReactDOM.render(<App pageSize={
    
    20} />,document.getElementById('root')
)

5. 组件的生命周期

组件生命周期概述

  1. 组件的生命周期:组件从被创建到挂载到页面中运行,再到组件不用时卸载的过程,这个过程就叫做组件的生命周期。react在组件的生命周期中提供了一系统的钩子函数,可以让开发者在函数中注入代码,这些代码会在适当的时候运行。为开发人员在不同阶段操作组件提供了时机。
  2. 注意只有类组件才有生命周期。函数组件每次都是重新运行函数,旧的组件即刻被销毁

生命周期的三个阶段

组件的生命周期可以被分为3个阶段:挂载阶段、更新阶段、卸载阶段

  1. 每个阶段的执行时机
  2. 每个阶段钩子函数的执行顺序
  3. 每个阶段钩子函数的作用

挂载阶段:

  1. 执行时机:组件创建时(页面加载时)
  2. 钩子函数执行顺序:
constructor() --> render() --> componentDidMount()
钩子函数 触发时机 作用
constructor() 创建组件时,最先执行 1. 初始化state 。2. 为事件处理程序绑定this
render() 每次组件渲染都会触发 渲染UI(注意:不能调用setState()
componentDidMount() 组件挂载(完成DOM渲染)后 1. 发送网络请求。2. DOM操作

1. constructor(): 是ES6中class的构造方法,组件被创建时会首先调用组件的构造方法 ,作用是初始化state,以及为事件处理程序绑定this
2. render():

  1. render()方法中,根据组件的props和state返回一个React元素,用于描述组件的UI,通常React元素使用JSX语法定义,实际上是调用React.creatElement()(JSX仅仅是createElement方法的语法糖,JSX语法被@babel/preset-react插件编译为creatElement方法,然后生成一个react元素)
  2. render()方法的作用是渲染UI
  3. 注意:在render()里面不能调用setState() componentDidMount()

3. componentDidMount():

  1. componentDidMount()是在组件被挂载在DOM之后调用,而且只会被调用一次。这个时候已经获取到了DOM结构,因此依赖DOM节点的操作就可以放在这个方法里面去实现。(在这一阶段,虚拟DOM已经挂载到了页面上成为了真实DOM)
  2. 可以调用setState()
  3. componentDidMount()方法的作用是:向服务器端发送网络请求,以及处理依赖DOM节点的操作

更新阶段:

  1. 执行时机: 1. setState() 2. forceUpdate() 3. 组件接收到新的props
  2. 说明:以上三者任意一种变化,组件就会重新渲染
  3. 执行顺序:
render() --> componentDidUpdate()
钩子函数 触发时机 作用
render() 每次组件渲染都会触发 渲染UI(与挂载阶段是同一个render())
componentDidUpdate() 组件更新(完成DOM渲染)后 1.发送网络请求。 2. DOM操作。注意:如果要setState()必须放在一个if条件中
if(prevProps.count !== this.props.count){
    
    
this.setState({
    
    })
}

组件被挂载到DOM之后,props和state都可以引起组件的更新。props引起的组件更新,本质上是由渲染该组件的父组件引起的,无论props是否改变,当父组件的render()方法每一次被调用时,都会导致组件的更新。State引起的组件更新,则是通过调用this.setState()修改组件的state来触发的。因此,父组件调用render方法或者调用this.setState都会引起组件的更新

卸载时(卸载阶段):
执行时机:组件从页面中消失

钩子函数 触发时机 作用
componentWillUnmount 组件卸载(从页面中消失) 执行清理工作(比如:清理定时器等)

6. render-props和高阶组件

通常组件复用有两种方式:

  1. 使用render props模式
  2. 高阶组件(HOC)

注意:这两种方式不是新的APOI,而是利用React自身的特点的编码技巧,演化而成的固定模式(写法)

复用什么?

  1. state
  2. 操作state的方法(组件状态逻辑)

render props模式:

  1. 创建要复用的组件,在组件中提供状态和操作状态的方法
  2. 将要复用的状态作为props.render(state)的参数暴露出去
  3. 注意:提供的render函数必须有返回值,另外如果将jsx写为组件的子节点,则父组件可以用this.props.children的形式

问题:

  1. 如何拿到该组件中复用的state? 在使用组件时,添加一个值为函数的prop,通过函数参数来获取(需要组件内部实现)
  2. 如何渲染任意的UI? 使用该函数的返回值作为要渲染的UI内容(需要组件内部实现)
<Mouse render={
    
     (mouse)=>{
    
    } }
<Mouse render={
    
    (mouse)=>(<p>鼠标当前位置{
    
    mouse.x},{
    
    mouse.y}</p>)}/>

render props模式使用步骤:

  1. 创建Mouse组件,在组件中提供复用的状态逻辑代码(1. 状态 2. 操作状态的方法)
  2. 将要复用的状态作为props.render(state)方法的参数,暴露到组件外部
  3. 使用props.render()返回值作为要渲染的内容
class Mouse extends React.Component{
    
    
    //省略state和操作state的方法
    render(){
    
    
        // return null
        return this.props.render(this.state)
    }
}
<Mouse render={
    
    (mouse)=><p>鼠标当前位置{
    
    mouse.x},{
    
    mouse.y}</p>}/>

代码实现:

import React from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'
// 导入图片资源
import img form './文件路径'

// 创建Mouse组件
class Mouse extends React.Component{
    
    
    // 鼠标位置state
    state = {
    
    
        x:0,
        y:0
    }
    // 鼠标移动事件的事件处理程序
    handleMouseMove = e=>{
    
    
        this.setState({
    
    
            x:e.clientx,
            y:e.clienty
        })
    }
    // 监听鼠标移动事件
    componentDidMount(){
    
    
        window.addEventListener('mousemove',this.handleMouseMove)
    }
    render(){
    
    
        // return null
        return this.props.chlidren(this.state)
    }
}
// 添加props校验
Mouse.prototypes={
    
    
    chlidren:PropTypes.func.isRequired
}

class App extends React.Component{
    
    
    render(){
    
    
        return(
            <div>
                <h1>render props模式</h1>
                <Mouse 
                render={
    
    mouse =>{
    
    
                    return(
                        <p>
                            鼠标位置:{
    
    mouse.x} {
    
    mouse.y}
                        </p>
                    )
                    }}
                />
                // {猫捉老鼠}
                <Mouse render={
    
    mouse =>{
    
    return <img src={
    
    img} alt="猫"/>
            }}></Mouse>
            </div>
        )
    }
 
}

ReactDOM.render(<App/>,document.getElementById('root'))

演示Mouse组件的复用:

  1. Mouse组件负责:封装复用的状逻辑代码(1. 状态 2. 操作状态的方法)
  2. 状态:鼠标坐标(x, y)
  3. 操作状态的方法:鼠标移动事件
  4. 传入的render prop负责:使用复用的状态来渲染UI结构

children代替render属性:

  1. 注意:并不是该模式叫render props就必须使用名为render的prop,实际上可以使用任意名称的prop
  2. 把prop是一个函数并且告诉组件要渲染什么内容的技术叫做:render props模式
  3. 推荐:使用childe
   <Mouse>
    {
    
    ({
     
     x,y})=> <p>鼠标的位置是:{
    
    x},{
    
    y}</p>}
    </Mouse> 
    // 组件内部
    this.props.children(this.state)

代码优化:

  1. 推荐:给render props模式添加props校验
  2. 应该在组件卸载时解除mousemove事件绑定
// 添加props校验
Mouse.prototypes={
    
    
    chlidren:PropTypes.func.isRequired
}
 //推荐:在组件卸载时移除事件绑定
 componentWillUnmount(){
    
    
 	window.removeEventListener('mousemove',this.handleMouseMove)
}

代码实现:

import React from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'
// 导入图片资源
import img form './文件路径'

// 创建Mouse组件
class Mouse extends React.Component{
    
    
    // 鼠标位置state
    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(){
    
    
        // return null
        return this.props.chlidren(this.state)
    }
}
// 添加props校验
Mouse.prototypes={
    
    
    chlidren:PropTypes.func.isRequired
}

class App extends React.Component{
    
    
    render(){
    
    
        return(
            <div>
                <h1>render props模式</h1>
                <Mouse 
                render={
    
    mouse =>{
    
    
                    return(
                        <p>
                            鼠标位置:{
    
    mouse.x} {
    
    mouse.y}
                        </p>
                    )
                    }}
                />
                // {猫捉老鼠}
                <Mouse render={
    
    mouse =>{
    
    return <img src={
    
    img} alt="猫"/>
            }}></Mouse>
            </div>
        )
    }
 
}


ReactDOM.render(<App/>,document.getElementById('root'))


高阶组件(HOC)

  1. 高阶组件一个函数,在函数中有可复用的类组件,通过props将可复用的状态传给被包装组件
  2. 高阶组件内部创建一个类组件,在这个类组件中提供复用的状态逻辑代码,通过prop将复用的状态传递给被包装组件WrappedComponent

高阶组件(HOC)使用步骤:

  1. 创建一个函数,一般使用with开头便于区分
function withMouse() {
    
    }
  1. 给函数传入一个参数,该参数为将要渲染的组件,因此命名应该以大写字母开头
function withMouse(WrappedComponent) {
    
    }
  1. 在这个函数内部中创建一个类组件,提供需要复用的状态和操作状态的方法并返回
function withMouse(WrappedComponent) {
    
    
	class Mouse extends React.Component {
    
    }
return Mouse
}
  1. 在该组件中渲染作为参数传入的组件,并通过展开运算符的方式将复用的状态作为参数组件的属性(将状态通过prop传递给参数组件
function withMouse(WrappedComponent) {
    
    
	class Mouse extends React.Component {
    
    
	// Mouse组件的render方法中:
	return <WrappedComponent {
    
    ...this.state} />}
return Mouse
}
  1. 调用该高阶组件函数并传入需要增强的组件,即可返回添加复用参数和方法后的组件
// 创建组件
const MousePosition = withMouse(Position)
// 最后渲染组件
<MousePosition />

注意:在使用React调试工具进行调试时,为区分高阶组件得到的组件名称,需要设置displayName来进行区分。

设置displayName

  1. 使用高阶组件存在的问题:得到的两个组件名称相同
  2. 原因:默认情况下,React使用组件名称作为 displayName
  3. 解决方式:为 高阶组件 设置displayName便于调试时区分不同的组件
  4. displayName的作用:用于设置调试信息(React Developer Tools信息)
Mouse.displayName = `WithMouse${
      
      getDisplayName(WrappedComponent)}`

function getDisplayName(WrappedComponent) {
    
    
	return WrappedComponent.displayName || WrappedComponent.name || 'Component'
}

传递props:

  1. 问题:props丢失
  2. 原因:高阶组件没有往下传递props
  3. 解决方式:渲染 WrappedComponent 时,将 statethis.props 一起传递给组件

传递方式:

<WrappedComponent {
    
    ...this.state} {
    
    ...this.props} />

代码实现:

import React from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'

// 创建高阶组件
function withMouse(WrappedComponent){
    
    
    // 该组件提供复用的状态逻辑
    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(){
    
    
            传递props
            return <WrappedComponent {
    
    ...this.state} {
    
    ...this.props}></WrappedComponent> 
        }
    }
    // 设置didplayName
    Mouse.displayName = `WithMouse${
      
      getDisplayName(WrappedComponent)}`

    return Mouse
}


function getDidplayName(WrappedComponent){
    
    
    return WrappedComponent.getDidplayName || WrappedComponent.name || 'Component'
}

// 用来测试高阶组件
const Position = props=>{
    
    
    <p>鼠标当前位置:(x:{
    
    props.x},y:{
    
    props.y})</p>
}

const Cat = props=>{
    
    
    <img
    src={
    
    img}
    alt=""
    style={
    
    {
    
    
        position:'absolute',
        top:props.y-64,
        left:props.x-64
    }}
    />
}


// 获取增强后的组件
const MousePosition = withMouse(Position)

// 调用高阶组件来增强猫捉老鼠的组件
const MouseCat = withMouse(Cat)

class App extends React.Component{
    
    
    render(){
    
     
        return(
            <div>
                <h1>高阶组件</h1>
                {
    
    /* 渲染增强后的组件 */}
                <MousePosition a="1"/>
                <MouseCat />
            </div>
        )
    }
}

ReactDOM.render(<App />,document.getElementById('root'))


猜你喜欢

转载自blog.csdn.net/qiqizgl777/article/details/129361490
今日推荐