React高阶组件

一、认识高阶组件

什么是高阶组件呢? 相信很多人都听说过,也用过 高阶函数,它们非常相似,所以我们可以先来回顾一下什么是 高阶函数。

高阶函数的维基百科定义:至少满足以下条件之一:

  • 接受一个或多个函数作为输入;
  • 输出一个函数;

JavaScript中比较常见的filter、map、reduce都是高阶函数。

那么什么是高阶组件呢?

  • 高阶组件的英文是 Higher-Order Components,简称为 HOC;
  • 官方的定义:高阶组件是参数为组件,返回值为新组件的函数

我们可以进行如下的解析:

  • 首先, 高阶组件 本身不是一个组件,而是一个函数
  • 其次,这个函数的参数是一个组件返回值也是一个组件

二、高阶组件的定义

  • 高阶组件的调用过程类似于这样:
    在这里插入图片描述
  • 高阶函数的编写过程类似于这样:
    在这里插入图片描述
    在这里插入图片描述

组件的名称问题:

  • 在ES6中,类表达式中类名是可以省略的;
  • 组件的名称都可以通过displayName来修改;
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
import React, { PureComponent } from 'react';
class App extends PureComponent {
    render() {
        return (
            <div>
                app: {this.props.name}
            </div>
        );
    }
}

function enhanceComponent2(WrappedComponent) {
    function NewComponent(props) {
        return <WrappedComponent {...props} />
    }
    NewComponent.displayName = 'zep2'
    return NewComponent
}

// function enhanceComponent(WrappedComponent) {
//     class NewComponent extends PureComponent {
//         render() {
//             return <WrappedComponent {...this.props} />
//         }
//     }
//     NewComponent.displayName = 'zep'
//     return NewComponent
// }
const EnhanceComponent = enhanceComponent2(App)
export default EnhanceComponent;

高阶组件并不是React API的一部分,它是基于React的 组合特性而形成的设计模式;

高阶组件在一些React第三方库中非常常见:

  • 比如redux中的connect;(后续会讲到)
  • 比如react-router中的withRouter;(后续会讲到)

三、高阶组件的应用—— props的增强

不修改原有代码的情况下,添加新的props:
在这里插入图片描述
在这里插入图片描述

利用高阶组件来共享Context:

  1. 未使用高阶组件共享Context时:
import React, {PureComponent, createContext} from 'react';
// 创建Context
const UserContext = createContext({
    nickname: '默认',
    level: -1,
    region: '中国'
})
class Home extends PureComponent {
    render() {
        return (
            <UserContext.Consumer>
                {
                    user => {
                        return <h2>Home {`昵称:${user.nickname} 等级:${user.level} 区域:${user.region}`}</h2>
                    }
                }
            </UserContext.Consumer>
        )
    }
}
class About extends PureComponent {
    render() {
        return (
            <UserContext.Consumer>
                {
                    user => {
                        return <h2>Home {`昵称:${user.nickname} 等级:${user.level} 区域:${user.region}`}</h2>
                    }
                }
            </UserContext.Consumer>
        )
    }
}
class App extends PureComponent {
    render() {
        return (
            <div>
                app
                <UserContext.Provider value={{nickname: 'zep', level: 50, region: '深圳'}}>
                    <Home/>
                    <About/>
                </UserContext.Provider>
            </div>
        );
    }
}
export default App;

在这里插入图片描述

  1. 使用高阶组件共享Context时:
    在这里插入图片描述
    在这里插入图片描述
import React, {PureComponent, createContext} from 'react';
// 定义高阶组件
function withUser(WrappedComponent) {
    return function (props) {
        return (
            <UserContext.Consumer>
                {
                    user => {
                        return <WrappedComponent {...props} {...user} />
                    }
                }
            </UserContext.Consumer>
        )
    }
}

// 创建Context
const UserContext = createContext({
    nickname: '默认',
    level: -1,
    region: '中国'
})
class Home extends PureComponent {
    render() {
        return <h2>Home {`昵称:${this.props.nickname} 等级:${this.props.level} 区域:${this.props.region}`}</h2>

    }
}
class About extends PureComponent {
    render() {
        return <h2>Home {`昵称:${this.props.nickname} 等级:${this.props.level} 区域:${this.props.region}`}</h2>

    }
}
const UserHome = withUser(Home)
const UserAbout = withUser(About)
class App extends PureComponent {
    render() {
        return (
            <div>
                app
                <UserContext.Provider value={{nickname: 'zep', level: 50, region: '深圳'}}>
                    <UserHome/>
                    <UserAbout/>
                </UserContext.Provider>
            </div>
        );
    }
}
export default App;

四、高阶组件的应用—— 渲染判断鉴权

在开发中,我们可能遇到这样的场景:

  • 某些页面是必须用户登录成功才能进行进入;
  • 如果用户没有登录成功,那么直接跳转到登录页面;

这个时候,我们就可以使用高阶组件来完成鉴权操作:
在这里插入图片描述

import React, {PureComponent} from 'react';
// 高阶组件
function withAuth (WrappedComponent) {
    const NewCpn =  function (props) {
        const {isLogin} = props
        if (isLogin) {
            return <WrappedComponent {...props} />
        } else {
            return <LoginPage {...props} />
        }
    }
    NewCpn.displayName = 'AuthCpn'
    return NewCpn
}
// 登录组件
class LoginPage extends PureComponent {
    render() {
        return <h2>LoginPage</h2>
    }
}
// 购物车组件
class CartPage extends PureComponent {
    render() {
        return <h2>CartPage</h2>
    }
}
const AuthCartPage = withAuth(CartPage)
class App extends PureComponent {
    render() {
        return (
            <div>
                <AuthCartPage isLogin={false} />
            </div>
        );
    }
}
export default App;

五、高阶组件的应用—— 生命周期劫持

我们也可以利用高阶函数来劫持生命周期,在生命周期中完成自己的逻辑:
在这里插入图片描述

import React, {PureComponent} from 'react';
function withRenderTime(WrappedComponent) {
    return class extends PureComponent {
        // 即将渲染时获取当前的时间
        componentWillMount() {
            this.beginTime = Date.now()
        }
        // 渲染完成再获取当前时间
        componentDidMount() {
            this.endTime = Date.now()
            const interval = this.endTime - this.beginTime
            console.log(`${WrappedComponent.name}渲染时间: ${interval}`)
        }
        render() {
            return <WrappedComponent {...this.props} />
        }
    }
}
class Home extends PureComponent{
   /* // 即将渲染时获取当前的时间
    componentWillMount() {
        this.beginTime = Date.now()
    }*/
    render() {
        return <h2>Home</h2>
    }
    /*// 渲染完成再获取当前时间
    componentDidMount() {
        this.endTime = Date.now()
        const interval = this.endTime - this.beginTime
        console.log('Home渲染时间:' + interval)
    }*/
}
class About extends PureComponent{
    render() {
        return <h2>About</h2>
    }
}
const TimeHome = withRenderTime(Home)
const TimeAbout = withRenderTime(About)
class App extends PureComponent {
    render() {
        return (
            <div>
                App
                <TimeHome />
                <TimeAbout />
            </div>
        );
    }
}
export default App;

六、高阶函数的意义

我们会发现利用高阶组件可以针对某些React代码进行更加优雅的处理。
其实早期的React有提供组件之间的一种复用方式是mixin,目前已经不再建议使用:

  • Mixin 可能会相互依赖,相互耦合,不利于代码维护
  • 不同的Mixin中的方法可能会相互冲突
  • Mixin非常多时,组件是可以感知到的,甚至还要为其做相关处理,这样会给代码造成滚雪球式的复杂性

当然,HOC也有自己的一些缺陷:

  • HOC需要在原组件上进行包裹或者嵌套,如果大量使用HOC,将会产生非常多的嵌套,这让调试变得非常困难;
  • HOC可以劫持props,在不遵守约定的情况下也可能造成冲突;

Hooks的出现,是开创性的,它解决了很多React之前的存在的问题

  • 比如this指向问题
  • 比如hoc的嵌套复杂度问题等
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值