diff --git a/src/hooks/usePerformanceTracker.ts b/src/hooks/usePerformanceTracker.ts new file mode 100644 index 00000000..6d2fcf79 --- /dev/null +++ b/src/hooks/usePerformanceTracker.ts @@ -0,0 +1,129 @@ +/** + * React 性能追踪 Hooks + * 封装 performanceMonitor 工具,提供 React 友好的性能追踪 API + */ + +import { useEffect, useRef, useCallback } from 'react'; +import { performanceMonitor } from '@utils/performanceMonitor'; + +/** + * usePerformanceMark 返回值类型 + */ +export interface UsePerformanceMarkReturn { + /** 标记时间点 */ + mark: (suffix: string) => void; + /** 测量并记录到 performanceMonitor */ + measure: (startSuffix: string, endSuffix: string, name?: string) => number | null; + /** 获取测量值(不记录) */ + getMeasure: (startSuffix: string, endSuffix: string) => number | null; +} + +/** + * usePerformanceTracker - 自动追踪组件渲染性能 + * + * @param componentName - 组件名称,用于标记 + * @param options - 配置选项 + * + * @example + * ```tsx + * function MyComponent() { + * usePerformanceTracker('MyComponent'); + * return
...
; + * } + * ``` + * + * 自动标记: + * - {componentName}-mount: 组件挂载时 + * - {componentName}-rendered: 首次渲染完成 + * - {componentName}-unmount: 组件卸载时 + */ +export function usePerformanceTracker( + componentName: string, + options: { trackRender?: boolean } = {} +): void { + const { trackRender = true } = options; + const hasMounted = useRef(false); + + // 首次渲染时立即标记(同步) + if (!hasMounted.current) { + performanceMonitor.mark(`${componentName}-mount`); + } + + useEffect(() => { + if (!hasMounted.current) { + hasMounted.current = true; + + // 渲染完成标记(在 useEffect 中,表示 DOM 已更新) + if (trackRender) { + performanceMonitor.mark(`${componentName}-rendered`); + performanceMonitor.measure( + `${componentName}-mount`, + `${componentName}-rendered`, + `${componentName} 渲染` + ); + } + } + + // 组件卸载时标记 + return () => { + performanceMonitor.mark(`${componentName}-unmount`); + }; + }, [componentName, trackRender]); +} + +/** + * usePerformanceMark - 手动标记自定义操作的性能 + * + * @param prefix - 标记前缀,用于区分不同操作 + * @returns 包含 mark、measure、getMeasure 方法的对象 + * + * @example + * ```tsx + * function MyComponent() { + * const { mark, getMeasure } = usePerformanceMark('api-call'); + * + * const handleFetch = async () => { + * mark('start'); + * await fetchData(); + * mark('end'); + * const duration = getMeasure('start', 'end'); + * console.log('API耗时:', duration, 'ms'); + * }; + * + * return ; + * } + * ``` + */ +export function usePerformanceMark(prefix: string): UsePerformanceMarkReturn { + const mark = useCallback( + (suffix: string) => { + performanceMonitor.mark(`${prefix}-${suffix}`); + }, + [prefix] + ); + + const measure = useCallback( + (startSuffix: string, endSuffix: string, name?: string) => { + return performanceMonitor.measure( + `${prefix}-${startSuffix}`, + `${prefix}-${endSuffix}`, + name || `${prefix}: ${startSuffix} → ${endSuffix}` + ); + }, + [prefix] + ); + + const getMeasure = useCallback( + (startSuffix: string, endSuffix: string) => { + return performanceMonitor.measure( + `${prefix}-${startSuffix}`, + `${prefix}-${endSuffix}` + ); + }, + [prefix] + ); + + return { mark, measure, getMeasure }; +} + +export default usePerformanceTracker;