Skip to main content

API Reference

Complete reference for all React Dev Debugger APIs, hooks, and utilities.

Tracked Hooks

useTrackedState

Drop-in replacement for React's useState with automatic state tracking.

function useTrackedState<T>(
initialValue: T | (() => T),
debugLabel?: string
): [T, (value: T | ((prev: T) => T)) => void]

Parameters:

  • initialValue: Initial state value or lazy initializer function
  • debugLabel (optional): Human-readable label for debugging

Returns:

  • Tuple of [state, setState] identical to useState

Example:

const [count, setCount] = useTrackedState(0, 'counter');
const [user, setUser] = useTrackedState(() => loadUser(), 'currentUser');

useTrackedReducer

Drop-in replacement for React's useReducer with action tracking.

function useTrackedReducer<S, A>(
reducer: (state: S, action: A) => S,
initialState: S,
debugLabel?: string
): [S, (action: A) => void]

// With lazy initialization
function useTrackedReducer<S, A, I>(
reducer: (state: S, action: A) => S,
initialArg: I,
init: (arg: I) => S,
debugLabel?: string
): [S, (action: A) => void]

Parameters:

  • reducer: Pure function that takes state and action, returns new state
  • initialState or initialArg: Initial state or argument for initializer
  • init (optional): Lazy initializer function
  • debugLabel (optional): Human-readable label

Returns:

  • Tuple of [state, dispatch] identical to useReducer

Example:

const [state, dispatch] = useTrackedReducer(
todoReducer,
[],
'todos'
);

dispatch({ type: 'ADD_TODO', text: 'Learn React' });

useTrackedContext

Track context consumption in components.

function useTrackedContext<T>(
context: React.Context<T>,
debugLabel?: string
): T

Parameters:

  • context: React Context object
  • debugLabel (optional): Human-readable label

Returns:

  • Current context value

Example:

const ThemeContext = createContext<Theme>(defaultTheme);

function ThemedButton() {
const theme = useTrackedContext(ThemeContext, 'theme');
return <button style={{ background: theme.primary }}>Click</button>;
}

useWhyDidYouUpdate

Debug hook that logs which props caused a component to re-render.

function useWhyDidYouUpdate(
componentName: string,
props: Record<string, any>
): void

Parameters:

  • componentName: Name to display in logs
  • props: Object containing all props to track

Example:

function ExpensiveComponent({ data, filters, onUpdate }) {
useWhyDidYouUpdate('ExpensiveComponent', { data, filters, onUpdate });

// Component logic...
}

Console Output:

[ExpensiveComponent] Props changed:
- data: {...} -> {...}
- filters: {...} -> {...}

useComponentId

Generate a stable unique ID for a component instance.

function useComponentId(prefix?: string): string

Parameters:

  • prefix (optional): String to prepend to the ID

Returns:

  • Stable unique identifier string

Example:

function MyComponent() {
const id = useComponentId('MyComponent');
console.log(id); // "MyComponent_abc123"
}

useRenderTracking

Track render performance for a component.

function useRenderTracking(
componentName: string,
slowThreshold?: number
): RenderMetrics

Parameters:

  • componentName: Name to display in performance logs
  • slowThreshold (optional): Milliseconds threshold for slow render warning (default: 16ms)

Returns:

  • Object containing render metrics:
    • renderCount: Total number of renders
    • averageTime: Average render duration in ms
    • lastTime: Most recent render duration in ms

Example:

function DataTable({ data }) {
const metrics = useRenderTracking('DataTable', 20);

useEffect(() => {
if (metrics.lastTime > 20) {
console.warn('Slow render detected!', metrics);
}
}, [metrics]);

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

Core APIs

StateTracker

Central state tracking system.

class StateTracker {
// Track a state update
trackUpdate(update: StateUpdate): void;

// Get all updates
getUpdates(): StateUpdate[];

// Get updates for a specific component
getComponentUpdates(componentId: string): StateUpdate[];

// Clear all tracked data
clear(): void;

// Subscribe to updates
subscribe(callback: (update: StateUpdate) => void): () => void;
}

// Access the singleton instance
const tracker = getStateTracker();

Example:

const tracker = getStateTracker();

// Subscribe to all updates
const unsubscribe = tracker.subscribe((update) => {
console.log('State updated:', update);
});

// Get all updates
const updates = tracker.getUpdates();
console.log(`Total updates: ${updates.length}`);

// Cleanup
unsubscribe();

Timeline

Manage chronological state history.

class Timeline {
// Get all timeline entries
getEntries(): TimelineEntry[];

// Get entry by index
getEntry(index: number): TimelineEntry | undefined;

// Get current index
getCurrentIndex(): number;

// Clear timeline
clear(): void;

// Subscribe to changes
subscribe(callback: () => void): () => void;
}

const timeline = getTimeline();

Example:

const timeline = getTimeline();

// Get all entries
const entries = timeline.getEntries();
entries.forEach((entry, index) => {
console.log(`${index}: ${entry.label} at ${entry.timestamp}`);
});

// Subscribe to changes
timeline.subscribe(() => {
console.log('Timeline updated!');
});

TimeTravel

Time-travel debugging functionality.

class TimeTravel {
// Jump to a specific point in history
goTo(index: number): void;

// Step backward
stepBack(): void;

// Step forward
stepForward(): void;

// Pause/resume tracking
pause(): void;
resume(): void;
isPaused(): boolean;

// Get current position
getCurrentIndex(): number;
getTotalSteps(): number;

// Check if can move
canStepBack(): boolean;
canStepForward(): boolean;
}

const timeTravel = getTimeTravel();

Example:

const timeTravel = getTimeTravel();

// Go to beginning
timeTravel.goTo(0);

// Step through history
if (timeTravel.canStepForward()) {
timeTravel.stepForward();
}

// Pause tracking temporarily
timeTravel.pause();
// ... do something ...
timeTravel.resume();

DependencyGraph

Component and state relationship graph.

class DependencyGraph {
// Add a component node
addComponent(node: ComponentNode): void;

// Add a state node
addState(node: StateNode): void;

// Add a connection
addEdge(from: string, to: string, type: EdgeType): void;

// Get graph data
getNodes(): Node[];
getEdges(): Edge[];

// Query relationships
getComponentStates(componentId: string): StateNode[];
getStateDependents(stateId: string): ComponentNode[];

// Clear graph
clear(): void;
}

const graph = getDependencyGraph();

Example:

const graph = getDependencyGraph();

// Get all components
const components = graph.getNodes().filter(n => n.type === 'component');

// Find what depends on a state
const dependents = graph.getStateDependents('myState');
console.log('Components using this state:', dependents);

SnapshotStore

Store and manage state snapshots for time-travel.

class SnapshotStore {
// Save a snapshot
save(snapshot: Snapshot): void;

// Get snapshot by index
get(index: number): Snapshot | undefined;

// Get all snapshots
getAll(): Snapshot[];

// Restore a snapshot
restore(index: number): void;

// Export snapshots
export(): string;

// Import snapshots
import(data: string): void;

// Clear all
clear(): void;
}

const store = getSnapshotStore();

Example:

const store = getSnapshotStore();

// Export current history
const json = store.export();
localStorage.setItem('debug-session', json);

// Later: restore the session
const saved = localStorage.getItem('debug-session');
if (saved) {
store.import(saved);
}

// Restore to a specific point
store.restore(5);

Global API

Access the debugger via the global window object:

interface ReactStateDebuggerAPI {
// Time-travel controls
goTo(index: number): void;
stepBack(): void;
stepForward(): void;

// Tracking controls
pause(): void;
resume(): void;
isPaused(): boolean;

// Data access
getUpdates(): StateUpdate[];
getTimeline(): TimelineEntry[];
getGraph(): { nodes: Node[]; edges: Edge[] };

// Export/Import
exportSnapshot(): string;
importSnapshot(data: string): void;

// Utilities
clear(): void;
showPanel(): void;
hidePanel(): void;
}

// Access globally
window.__REACT_STATE_DEBUGGER__

Example:

// In browser console or your code
const api = window.__REACT_STATE_DEBUGGER__;

// Export current session
const snapshot = api.exportSnapshot();
console.log('Snapshot:', snapshot);

// Jump to a specific state
api.goTo(10);

// Clear everything
api.clear();

Utility Functions

deepDiff

Calculate deep differences between two objects.

function deepDiff(
prev: any,
next: any
): DiffResult

Returns:

interface DiffResult {
added: string[]; // Newly added paths
removed: string[]; // Removed paths
changed: Change[]; // Modified paths with values
}

interface Change {
path: string;
prevValue: any;
nextValue: any;
}

Example:

import { deepDiff } from 'react-dev-debugger';

const prev = { name: 'John', age: 30 };
const next = { name: 'John', age: 31, city: 'NYC' };

const diff = deepDiff(prev, next);
// {
// added: ['city'],
// removed: [],
// changed: [{ path: 'age', prevValue: 30, nextValue: 31 }]
// }

formatValue

Format any value for display in the UI.

function formatValue(value: any, maxLength?: number): string

Example:

import { formatValue } from 'react-dev-debugger';

formatValue({ name: 'John' }); // "{ name: 'John' }"
formatValue([1, 2, 3]); // "[1, 2, 3]"
formatValue(null); // "null"
formatValue(undefined); // "undefined"

safeClone

Deep clone any value safely (handles circular references).

function safeClone<T>(value: T): T

Example:

import { safeClone } from 'react-dev-debugger';

const original = { data: [1, 2, 3], nested: { value: 42 } };
const cloned = safeClone(original);

cloned.nested.value = 99;
console.log(original.nested.value); // Still 42

TypeScript Types

All TypeScript type definitions are exported:

import type {
StateUpdate,
ComponentNode,
StateNode,
TimelineEntry,
Snapshot,
DiffResult,
HookType,
ExternalStoreType,
ReactStateDebuggerAPI,
} from 'react-dev-debugger';

Key Types

interface StateUpdate {
id: string;
timestamp: number;
componentName: string;
componentId: string;
hookType: HookType;
prevValue: unknown;
nextValue: unknown;
label?: string;
actionType?: string;
}

interface ComponentNode {
id: string;
name: string;
parentId?: string;
states: StateNode[];
renderCount: number;
lastRenderDuration: number;
averageRenderDuration: number;
}

interface TimelineEntry {
index: number;
update: StateUpdate;
snapshot: Snapshot;
timestamp: number;
}

Environment Detection

The debugger automatically detects the environment:

import { isDevelopment, isBrowser } from 'react-dev-debugger';

if (isDevelopment() && isBrowser()) {
// Debugger is active
}

The debugger is automatically disabled when:

  • process.env.NODE_ENV === 'production'
  • Running in a non-browser environment (SSR, Node.js)

Next Steps