构建 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...

相关推荐
阿丽塔~8 分钟前
react中 useEffect和useLayoutEffect的区别
前端·react.js·前端框架
Evrytos2 小时前
探索 React 的生长逻辑 - React 渲染原理
react.js
Evrytos3 小时前
React Hook & 周边技术原理
react.js
本地跑没问题7 小时前
HashRouter和BrowserRouter对比
前端·javascript·react.js
walking9577 小时前
React useEffect 使用场景示例
前端·react.js
咔咔库奇7 小时前
【react】实现路由返回拦截的多种方式
前端·react.js·前端框架
YiHanXii7 小时前
在 React 中,组件之间传递变量的常见方法
前端·javascript·react.js
关山月19 小时前
React 服务端流式渲染
react.js
萌萌哒草头将军19 小时前
🔥🔥🔥Alova.js 现代化请求库完全指南
前端·vue.js·react.js