Skip to main content

React Hooks

@simplelogs/next ships a set of React hooks for common browser measurement patterns. All hooks require the Provider to be in the tree.

All hooks are "use client" — they must be called from client components.


usePageLoadTime(options?)

Measures the time from navigation start to full page load (or to the first appearance of a specific DOM element).

'use client';

import { usePageLoadTime } from '@simplelogs/next';

export function PageLoadTracker() {
usePageLoadTime({
touchpoint: 'perf/page-load',
key: 'home-page-load',
});

return null;
}

Place this component anywhere in the page. It runs once and records a single timing entry.

UsePageLoadTimeOptions

FieldTypeDefaultDescription
selectorstringCSS selector. When provided, measures time until this element first appears in the DOM. When omitted, measures to window.load.
touchpointstringTouchpoint name
keystringCorrelation key
metadataRecord<string, unknown>Extra metadata

Without a selector — uses PerformanceNavigationTiming.loadEventEnd when available, falls back to Date.now() at the load event.

With a selector — uses a MutationObserver to detect the element's first appearance. Useful for measuring "time to interactive" for a specific UI region.


useComponentMountTime(options?)

Records the time from navigation start to when the component first mounts. Useful for measuring how long it takes for a critical component to render.

'use client';

import { useComponentMountTime } from '@simplelogs/next';

export function ProductGrid({ products }) {
useComponentMountTime({
touchpoint: 'perf/product-grid-mounted',
metadata: { count: products.length },
});

return <div>{/* ... */}</div>;
}

UseComponentMountTimeOptions

FieldTypeDescription
touchpointstringTouchpoint name
keystringCorrelation key
metadataRecord<string, unknown>Extra metadata

useTimedCallback(callback, options?)

Wraps any async or sync callback and automatically records how long each invocation takes. The timing is recorded even if the callback throws — the error is re-thrown after recording, with { error: true } merged into the metadata.

'use client';

import { useTimedCallback } from '@simplelogs/next';

export function SubmitButton({ onSubmit }) {
const timedSubmit = useTimedCallback(onSubmit, {
touchpoint: 'ui/form/submit',
key: 'checkout-submit',
});

return <button onClick={timedSubmit}>Submit</button>;
}

useTimedCallback returns a new async function with the same argument signature. It wraps the callback with useCallback, so you should pass a stable reference to avoid unnecessary re-renders (or add the callback to useMemo).

UseTimedCallbackOptions

FieldTypeDescription
touchpointstringTouchpoint name
keystringCorrelation key
metadataRecord<string, unknown>Extra metadata (merged with { error: true } on failure)

useWebVitals(options)

Monitors a single Core Web Vital via PerformanceObserver. Silently no-ops if the vital is not supported by the current browser.

'use client';

import { useWebVitals } from '@simplelogs/next';

export function WebVitalsTracker() {
useWebVitals({ vital: 'lcp', touchpoint: 'perf/lcp', key: 'home-lcp' });
useWebVitals({ vital: 'fcp', touchpoint: 'perf/fcp', key: 'home-fcp' });
useWebVitals({ vital: 'ttfb', touchpoint: 'perf/ttfb', key: 'home-ttfb' });
useWebVitals({ vital: 'cls', touchpoint: 'perf/cls', key: 'home-cls' });

return null;
}

Supported vitals

ValueVitalMeasurement
"lcp"Largest Contentful PaintRecorded as a timing (ms from navigation start)
"fcp"First Contentful PaintRecorded as a timing (ms from navigation start)
"ttfb"Time to First ByteRecorded as a timing (response start ms)
"cls"Cumulative Layout ShiftAccumulated and flushed as a log entry with { cls: number } in metadata on unmount

CLS is a score (0–∞), not a duration, so it is recorded as a log event rather than a timing entry. metadata.cls contains the cumulative score.

UseWebVitalsOptions

FieldTypeRequiredDescription
vital"fcp" | "lcp" | "ttfb" | "cls"YesWhich vital to observe
keystringNoCorrelation key
touchpointstringNoTouchpoint name
metadataRecord<string, unknown>NoExtra metadata

useSimpleLogs()

Returns the client logger singleton. Use this when you need direct access to log(), start(), end(), or record() inside a component.

const logger = useSimpleLogs();

See Client Logging for the full method reference.