• 9. React 高阶组件是什么, 和普通组件有什么区别, 适用什么场景?


    9. React 高阶组件是什么, 和普通组件有什么区别, 适用什么场景?

    官方解释

    高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分, 它是一种基于 React 的组合特性而形成的设计模式。

    高阶组件(HOC)就是一个函数, 且该函数接受一个组件作为参数, 并返回一个新的组件, 它只是一种组件的设计模式, 这种设计模式是由 react 自身的组合性质必然产生的。我们将它们称为纯组件, 因为它们可以接受任何动态提供的子组件, 但它们不会修改或复制其输入组件中的任何行为。

    // hoc的定义
    function withSubscription(WrappedComponent, selectData) {
        return class extends React.Component {
            constructor(props) {
                super(props);
                this.state = {
                    data: selectData(DataSource, props)
                };
            }
    
            // 一些通用的逻辑处理
            render() {
                // ... 并使用新数据渲染被包装的组件!
                return ;
            }
        };
    }
    
    // 使用
    const BlogPostWithSubscription = withSubscription(BlogPost, (DataSource, props) => DataSource.getBlogPost(props.id));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    HOC的优缺点

    • 优点: 逻辑服用、不影响被包裹组件的内部逻辑
    • 缺点: hoc 传递给被包裹组件的 props 容易和被包裹后的组件重名, 进而被覆盖

    适用场景

    • 代码复用, 逻辑抽象
    • 渲染劫持
    • State 抽象和更改
    • Props 更改

    具体应用例子

    权限控制

    利用高阶组件的条件渲染特性可以对页面进行权限控制, 权限控制一般分为两个维度:页面级别和页面元素级别。

    // HOC.js
    function withAdminAuth(WrappedComponent) {
        return class extends React.Component {
            state = {
                isAdmin: false,
            }
    
            async UNSAFE_componentWillMount() {
                const currentRole = await getCurrentUserRole();
                this.setState({
                    isAdmin: currentRole === 'Admin',
                });
            }
    
            render() {
                if (this.state.isAdmin) {
                    return ;
                } else {
                    return (
    您没有权限查看该页面, 请联系管理员!
    ); } } }; } // pages/page-a.js class PageA extends React.Component { constructor(props) { super(props); // something here... } UNSAFE_componentWillMount() { // fetching data } render() { // render page with data } } export default withAdminAuth(PageA); // pages/page-b.js class PageB extends React.Component { constructor(props) { super(props); // something here... } UNSAFE_componentWillMount() { // fetching data } render() { // render page with data } } export default withAdminAuth(PageB);
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    组件渲染性能追踪

    借助父组件子组件生命周期规则捕获子组件的生命周期, 可以方便的对某个组件的渲染时间进行记录。

    class Home extends React.Component {
        render() {
            return (

    Hello World.

    ); } } function withTiming(WrappedComponent) { return class extends WrappedComponent { constructor(props) { super(props); this.start = 0; this.end = 0; } UNSAFE_componentWillMount() { super.componentWillMount && super.componentWillMount(); this.start = Date.now(); } componentDidMount() { super.componentDidMount && super.componentDidMount(); this.end = Date.now(); console.log(`${WrappedComponent.name} 组件渲染时间为 ${this.end - this.start} ms`); } render() { return super.render(); } }; } export default withTiming(Home);
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    注意: withTiming 是利用反向继承实现的一个高阶组件, 功能是计算被包裹组件(这里是 Home 组件)的渲染时间。

    页面复用

    const withFetching = fetching => WrappedComponent => {
        return class extends React.Component {
            state = {
                data: [],
            }
    
            async UNSAFE_componentWillMount() {
                const data = await fetching();
                this.setState({
                    data,
                });
            }
    
            render() {
                return ;
            }
        }
    }
    
    // pages/page-a.js
    export default withFetching(fetching('science-fiction'))(MovieList);
    // pages/page-b.js
    export default withFetching(fetching('action'))(MovieList);
    // pages/page-other.js
    export default withFetching(fetching('some-other-type'))(MovieList);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
  • 相关阅读:
    AtCoder Beginner Contest 278「A」「B」「C」「D」「E」「F 对抗博弈」
    室内渲染的艺术:室内渲染的灵魂!
    国内DNS首选
    Java自定义异常类详解及示例
    2023八股每日一题(九月份)
    S级猫主食冻干测评出来了:希喂、K9、朗诺实测分享
    分布式存储系统之Ceph集群RadosGW基础使用
    mysql 日志分类详解
    自动微分----pytorch中的梯度运算与反向传播函数(预备知识)
    【毕业设计】机器视觉二维码识别检测 - python opencv
  • 原文地址:https://blog.csdn.net/m0_51180924/article/details/126578425