Skip to content

Repository files navigation

react-perf-hooks

A focused collection of React hooks for performance monitoring, profiling, and Core Web Vitals measurement.

npm version license CI bundle size

Live docs: react-perf-hooks docs website


Repository layout

This repository is a single-package library project. The npm package, Docusaurus docs, and examples share one root package.json, one pnpm-lock.yaml, and one node_modules directory.

react-perf-hooks/
├── src/            # library source plus Docusaurus UI files
├── docs/           # Docusaurus MDX documentation
├── examples/       # StackBlitz demos
├── static/         # Docusaurus static assets
├── docusaurus.config.ts
├── sidebars.ts
├── package.json
├── pnpm-lock.yaml
└── tsup.config.ts

Library type-checking is scoped to src/hooks, src/index.ts, and src/test-setup.ts. Docusaurus has its own tsconfig.docs.json.


Why react-perf-hooks?

Most hook libraries give you useDebounce and useLocalStorage. This one does one thing: helps you measure, diagnose, and understand performance in React apps.

All hooks are tree-shakeable, TypeScript-first, and have zero runtime dependencies (web-vitals is an optional peer dep).


Installation

npm install react-perf-hooks

For useWebVitals, also install the optional peer dependency:

npm install web-vitals

Requirements: React >= 16.8


Hooks

Hook What it solves Docs
useRenderTracker Find components that re-render too often and why Full docs
useAllocationTracker Detect potentially retained heavy objects after component unmount in development Full docs
useRenderBudget Warn when a single render commit exceeds a time budget (default: 16ms) Full docs
usePerformanceMark Precise timing of any code path via the Performance API Full docs
useComponentLifecycle Track mount/unmount timings and live component lifetime Full docs
useMemoProfiling Profile useMemo cache hits/misses and recomputation costs Full docs
useWebVitals Live Core Web Vitals (LCP, CLS, INP, FCP, TTFB) as React state Full docs
useINP Native Interaction to Next Paint tracking with PerformanceObserver event entries Full docs
useCLS Component-scoped Cumulative Layout Shift tracking for a specific DOM node Full docs
useLongTasks Log main-thread freezes over 50ms and attach them to the current screen Full docs
useMemoryStatus Monitor Chromium JavaScript heap usage and flag high memory pressure Full docs
useNetworkEfficiency Flag oversized Resource Timing payloads, with mobile network threshold adjustments Full docs
useDebouncedState Debounced useState with render-skip profiling counters Full docs
useThrottledState Throttled useState with dropped-update profiling counters Full docs
useIntersectionObserver Lazy-loading visibility state plus first-visible and total-visible metrics Full docs

See the docs overview for a complete reference.


Quick start

import { useEffect } from 'react';
import {
  useRenderTracker,
  useAllocationTracker,
  useRenderBudget,
  usePerformanceMark,
  useComponentLifecycle,
  useMemoProfiling,
  useWebVitals,
  useINP,
  useCLS,
  useLongTasks,
  useMemoryStatus,
  useNetworkEfficiency,
  useDebouncedState,
  useThrottledState,
  useIntersectionObserver,
} from 'react-perf-hooks';

function App() {
  // Track re-renders and warn if a component renders more than 10 times
  const { count } = useRenderTracker({ userId }, { name: 'App', warnAt: 10 });

  // Register heavyweight allocations for post-unmount GC diagnostics in development
  const trackAllocation = useAllocationTracker({ componentName: 'App' });

  useEffect(() => {
    const scratchBuffer = new Uint8Array(1024 * 1024 * 10);
    trackAllocation(scratchBuffer, 'scratch buffer');
  }, [trackAllocation]);

  // Warn when a render exceeds one frame budget (16ms by default)
  useRenderBudget(16, 'App');

  // Measure fetch duration with the Performance API
  const { mark, measure } = usePerformanceMark('App');

  // Track mount time and current lifetime of a component
  const { mountedAt, aliveMs } = useComponentLifecycle('App');

  // Profile whether this memoized computation is mostly cache HITs or MISSes
  const filteredUsers = useMemoProfiling(() => users.filter((u) => u.active), [users], 'ActiveUsers');

  // Subscribe to Core Web Vitals and report to analytics
  const vitals = useWebVitals({
    onMetric: (m) => navigator.sendBeacon('/analytics', JSON.stringify(m)),
  });

  // Track the current page's worst Interaction to Next Paint
  const inp = useINP({
    onMetric: (m) => navigator.sendBeacon('/analytics/inp', JSON.stringify(m)),
  });

  // Track Cumulative Layout Shift for one component root
  const cls = useCLS<HTMLDivElement>({
    onMetric: (m) => navigator.sendBeacon('/analytics/cls/component', JSON.stringify(m)),
  });

  // Log main-thread freezes and attach them to the current screen
  useLongTasks({
    screen: () => location.pathname,
    onLongTask: (m) => navigator.sendBeacon('/analytics/long-tasks', JSON.stringify(m)),
  });

  // Monitor Chromium heap telemetry and flag high memory pressure
  const memory = useMemoryStatus({ warningThresholdRatio: 0.8, interval: 5000 });

  // Warn when an API response payload is too large for current network conditions
  const network = useNetworkEfficiency({
    resourceFilter: '/api/v1/heavy-data',
    maxSizeInBytes: 1024 * 500,
    onWarning: (entry) => navigator.sendBeacon('/analytics/network-payload', JSON.stringify(entry)),
  });

  // Debounce state updates and inspect profiling counters
  const [query, setQuery, stats] = useDebouncedState('', 250);

  // Throttle high-frequency state while measuring discarded updates
  const [pointer, setPointer, pointerStats] = useThrottledState({ x: 0, y: 0 }, 120);

  // Track when an element first becomes visible and for how long it stays visible
  const { ref, isVisible, metrics } = useIntersectionObserver({ threshold: 0.25 });

  return <div ref={cls.ref}>...</div>;
}

Interactive demos live in examples/stackblitz/hooks-playground and are embedded from the docs site.


TypeScript

All hooks ship with full type declarations. No @types/* packages needed.

import type {
  RenderInfo,
  UseRenderTrackerOptions,
  AllocationLeakInfo,
  TrackAllocation,
  UseAllocationTrackerOptions,
  UseRenderBudgetOptions,
  PerformanceMeasureResult,
  UsePerformanceMarkReturn,
  ComponentLifecycleInfo,
  MemoProfilingStats,
  WebVitalMetric,
  WebVitalsState,
  UseWebVitalsOptions,
  VitalRating,
  INPMetric,
  INPRating,
  UseINPOptions,
  UseINPReturn,
  CLSAttribution,
  CLSMetric,
  CLSRating,
  UseCLSOptions,
  UseCLSReturn,
  LongTaskAttribution,
  LongTaskMetric,
  UseLongTasksOptions,
  UseLongTasksReturn,
  UseMemoryStatusOptions,
  UseMemoryStatusReturn,
  NetworkEfficiencyEntry,
  NetworkEffectiveType,
  NetworkResourceFilter,
  UseNetworkEfficiencyOptions,
  UseNetworkEfficiencyReturn,
  DebouncedStateStats,
  UseDebouncedStateReturn,
  ThrottledStateStats,
  UseThrottledStateOptions,
  UseThrottledStateReturn,
  IntersectionObserverMetrics,
  UseIntersectionObserverReturn,
} from 'react-perf-hooks';

Contributing

Contributions are welcome! Please open an issue first to discuss what you'd like to change.

pnpm install          # Install dependencies
pnpm test             # Run tests in watch mode
pnpm test:coverage    # Run tests once with coverage
pnpm type-check       # Type-check the library
pnpm docs:type-check  # Type-check the Docusaurus site
pnpm lint             # Lint
pnpm format           # Format with Prettier
pnpm build            # Build CJS + ESM + .d.ts
pnpm docs:build       # Build the docs site
pnpm run ci           # Run the library CI checks locally

Each hook lives in its own directory under src/hooks/. To add a new hook:

  1. Create src/hooks/useYourHook/index.ts
  2. Add tests in src/hooks/useYourHook/useYourHook.test.tsx
  3. Export from src/index.ts
  4. Add a doc in docs/hooks/use-your-hook.mdx and link it from sidebars.ts

License

MIT © Valentyn Yefimov

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages