【React】高阶组件

概述

高阶组件并非一个组件,而是增强组件功能的一个函数。

高阶组件的作用是对多个组件公共逻辑进行横向抽离。

高阶组件 – React (reactjs.org)

示例

ChildCom1.jsx

import React from 'react';

function ChildCom1(props) {

    return (
        <div>
            这是子组件1
           <div>姓名:{props.name}</div>
        </div>
    );
}

export default ChildCom1;

ChildCom2.jsx

import React from 'react';

function ChildCom1(props) {

    return (
        <div>
            这是子组件2
           <div>姓名:{props.age}</div>
        </div>
    );
}

export default ChildCom2;

withLog.js

import {useEffect} from "react";

/**
 * 日志打印(抽离为高阶组件)
 * @param Com 接收一个组件
 * @returns {(function())|*} 返回一个新组件
 */
export default function withLog(Com) {
    return function NewCom(props) {
        useEffect(() => {
            // 日志打印
            console.log(`${Com.name}已经创建,创建时间是:`, new Date().toLocaleString());
            return function () {
                // 组件销毁时执行
                console.log(`${Com.name}已经销毁,销毁时间是:`, new Date().toLocaleString());
            }
        }, []);
        // 一般来讲,传入的组件会作为新组件的视图返回
        return <Com {...props}/>
    }
}

withTimer.js

import {useEffect, useState} from "react";

export default function withTimer(Com) {
    return function  NewCom(props) {
        const [counter, setCounter] = useState(1)
        useEffect(() => {

            // 定时器
            const timer = setInterval(() => {
                console.log(counter)
                setCounter(counter + 1)
            }, 1000)
            return () => {
                clearInterval(timer)
            }
        }, [counter]);
        return <Com {...props} />
    }
}

App.js

import ChildCom1 from "./components/ChildCom1";
import ChildCom2 from "./components/ChildCom2";
import withLog from "./HOC/withLog";
import withTimer from "./HOC/withTimer";

const NewChildCom1 = withTimer(withLog(ChildCom1))
const NewChildCom2 = withTimer(withLog(ChildCom2))

function App() {
    return (
        <div className="App">
            <h1>我是 App</h1>
            <NewChildCom1 name={"xiuxiu"}/>
            <NewChildCom2 age={18}/>
        </div>
    );
}

export default App;

应用场景

Next 中,可以在 app/layout.tsx 中预留一个可以编写全局初始化逻辑的代码:

/**
 * 全局初始化函数,有全局单次调用的代码,都可以写到这里
 */
const doInit = useCallback(() => {
  console.log("hello 欢迎来到我的项目");
}, []);

// 只执行一次
useEffect(() => {
  doInit();
}, []);

开发环境中可能会看到 useEffect 执行了 2 次,这是正常现象,生产环境不会出现这个问题。

可以封装出一层 InitLayout,而不要把初始化逻辑直接写到 RootLayout 中,可以更好地维护初始化逻辑,防止后续扩展代码时出现执行时机的冲突。(比如引入全局状态管理后,要先执行 RootLayout 的 Provider 组件,才能获取到 useDispatch)

/**
 * 执行初始化逻辑的布局(多封装一层)
 * @param children
 * @constructor
 */
const InitLayout: React.FC<
  Readonly<{
    children: React.ReactNode;
  }>
> = ({ children }) => {
  /**
   * 全局初始化函数,有全局单次调用的代码,都可以写到这里
   */
  const doInit = useCallback(() => {
    console.log("hello 欢迎来到我的项目");
  }, []);
  
  // 只执行一次
  useEffect(() => {
    doInit();
  }, []);

  return <>{children}</>
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秀秀_heo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值