构建 useDebugLogger – 记录方法执行时间的 React Hook

调试 React 组件可能会变得复杂,尤其是当你试图弄清事件耗时多久或一个方法被调用了多少次时。如果我们能添加一个简单的 Hook 来记录以下信息,岂不美哉:

  • 组件挂载和卸载时间
  • 页面重新加载
  • 方法执行时长(以及调用次数)

这正是我们今天要构建的内容:一个自定义 Hook,名为 useDebugLogger

我们要构建的内容

我们要构建的 Hook 能够做到以下几点:

  • 记录组件挂载所需的时间(以毫秒为单位)。
  • 记录组件卸载的时间。
  • 记录用户重新加载页面的时间。
  • 记录任意函数(或异步方法)的执行时间以及被调用的次数。

它的使用方式如下:

jsx 复制代码
const { logMethodExecution } = useDebugLogger("Home");

const myMethod = logMethodExecution("myMethod", () => {
  // 你的逻辑代码
});

下面是我们的 useDebugLogger Hook 的完整代码:

jsx 复制代码
import { useEffect, useRef, useCallback } from "react";

const useDebugLogger = (componentName: string) => {
  const methodExecutionCount = useRef<Record<string, number>>({});

  // 记录挂载时间
  useEffect(() => {
    const mountStart = performance.now();
    const mountEnd = performance.now();
    console.log(
      `🔸 [${componentName}] 在 ${(mountEnd - mountStart).toFixed(2)}ms 内挂载`
    );

    return () => {
      const endTime = new Date().toLocaleTimeString();
      console.log(`🔸 [${componentName}] 在 ${endTime} 卸载`);
    };
  }, [componentName]);

  // 记录页面重新加载
  useEffect(() => {
    const reloadHandler = () => {
      const reloadTime = new Date().toLocaleTimeString();
      console.log(`🔸 [${componentName}] 在 ${reloadTime} 检测到重新加载`);
    };

    window.addEventListener("beforeunload", reloadHandler);
    return () => {
      window.removeEventListener("beforeunload", reloadHandler);
    };
  }, [componentName]);

  // 方法包装器:记录执行时间和调用次数
  const logMethodExecution = useCallback<
    <T extends (...args: unknown[]) => unknown>(methodName: string, method: T) => T
  >((methodName, method) => {
    return ((...args: Parameters<T>): ReturnType<T> => {
      methodExecutionCount.current[methodName] =
        (methodExecutionCount.current[methodName] || 0) + 1;
      const count = methodExecutionCount.current[methodName];

      const start = performance.now();
      console.log(
        `🔹 [${componentName}] ${methodName} 开始 (第 ${count} 次执行)`
      );

      const result = method(...args);

      if (result instanceof Promise) {
        return result.finally(() => {
          const end = performance.now();
          console.log(
            `🔹 [${componentName}] ${methodName} 在 ${(end - start).toFixed(
              2
            )}ms 后完成 (第 ${count} 次执行)`
          );
        }) as ReturnType<T>;
      } else {
        const end = performance.now();
        console.log(
          `🔹 [${componentName}] ${methodName} 在 ${(end - start).toFixed(
            2
          )}ms 后完成 (第 ${count} 次执行)`
        );
        return result as ReturnType<T>;
      }
    }) as T;
  }, [componentName]);

  return { logMethodExecution };
};

export default useDebugLogger;

逐步解析

1. 挂载时间记录

jsx 复制代码
useEffect(() => {
  const mountStart = performance.now();
  const mountEnd = performance.now();
  console.log(`[组件] 在 Xms 内挂载`);
}, []);

这部分代码记录了组件挂载所需的时间,使用 performance.now() 确保记录的准确性。

2. 卸载记录

jsx 复制代码
return () => {
  const endTime = new Date().toLocaleTimeString();
  console.log(`[组件] 在 HH:MM:SS 卸载`);
};

这部分代码在组件从 DOM 中移除时记录卸载时间。

3. 重新加载追踪

jsx 复制代码
useEffect(() => {
  const reloadHandler = () => {
    console.log(`[组件] 在 HH:MM:SS 检测到重新加载`);
  };
  window.addEventListener("beforeunload", reloadHandler);
  return () => window.removeEventListener("beforeunload", reloadHandler);
}, []);

这部分代码在用户刷新浏览器时记录重新加载的时间。

4. 方法记录器

jsx 复制代码
const logMethodExecution = useCallback((methodName, method) => {
  return (...args) => {
    // 记录开始时间
    const start = performance.now();

    // 记录调用次数
    // 执行方法并记录持续时间
  };
}, []);

每次方法执行时,你会得到以下信息:

  • 调用次数
  • 开始时间
  • 执行时长(精确到毫秒)

在组件中的示例用法

jsx 复制代码
const { logMethodExecution } = useDebugLogger("Home");

const fetchData = logMethodExecution("fetchData", async () => {
  const res = await fetch("https://jsonplaceholder.typicode.com/posts/1");
  const data = await res.json();
  console.log("获取的数据:", data);
});

return (
  <button onClick={fetchData}>获取数据</button>
);

控制台输出:

jsx 复制代码
🔹 [主页] fetchData 开始 (第 1 次执行)
获取的数据: { id: 1, title: ... }
🔹 [主页] fetchData 在 412.77ms 后完成 (第 1 次执行)

总结

useDebugLogger Hook 为你提供了对 React 组件行为的细致洞察。它是一种轻量级且优雅的方式,在开发过程中追踪性能,无需借助外部工具。

原文:dev.to/yassinek/bu...

相关推荐
谢尔登17 分钟前
React19事件调度的设计思路
前端·javascript·react.js
2301_7965125236 分钟前
【精通篇】打造React Native鸿蒙跨平台开发高级复合组件库开发系列:Lazyload 懒加载(懒加载的图片)
前端·javascript·react native·react.js·ecmascript·harmonyos
摘星编程1 小时前
OpenHarmony环境下React Native:Timeline时间轴组件
javascript·react native·react.js
摘星编程1 小时前
在OpenHarmony上用React Native:Timeline水平时间轴
javascript·react native·react.js
LZQ <=小氣鬼=>2 小时前
React + Ant Design (antd) 国际化完整实战教程
前端·react.js·前端框架·antd·moment
星海拾遗2 小时前
react源码从入门到入定
前端·javascript·react.js
●VON3 小时前
React Native for OpenHarmony:Pressable —— 构建下一代状态驱动交互的基石
学习·react native·react.js·性能优化·交互·openharmony
摘星编程3 小时前
React Native鸿蒙版:Calendar日历组件
react native·react.js·harmonyos
●VON3 小时前
React Native for OpenHarmony:解构 TouchableOpacity 的触摸反馈与事件流控制
javascript·学习·react native·react.js·性能优化·openharmony
2601_9495936512 小时前
基础入门 React Native 鸿蒙跨平台开发:模拟智能音响
react native·react.js·harmonyos