Advanced Features
Explore powerful advanced features of React Dev Debugger for complex debugging scenarios.
Custom State Tracking
Manual State Registration
Track state from any source:
import { getStateTracker } from 'react-dev-debugger';
const tracker = getStateTracker();
// Track custom state update
tracker.trackUpdate({
id: generateId(),
timestamp: Date.now(),
componentName: 'CustomComponent',
componentId: 'custom-1',
hookType: 'custom',
prevValue: oldValue,
nextValue: newValue,
label: 'customState',
renderCycleId: getRenderCycleId(),
});
Integration with Custom Libraries
class CustomStateManager {
constructor() {
this.listeners = [];
this.tracker = getStateTracker();
}
setState(newState) {
const prevState = this.state;
this.state = newState;
// Track the change
this.tracker.trackUpdate({
// ... update details
});
this.listeners.forEach(fn => fn(newState));
}
}
Snapshot Management
Export/Import Sessions
Save and restore debugging sessions:
import { getSnapshotStore } from 'react-dev-debugger';
const store = getSnapshotStore();
// Export current session
function saveSession() {
const data = store.export();
localStorage.setItem('debug-session', data);
// or download as file
downloadJSON(data, 'debug-session.json');
}
// Restore session
function loadSession() {
const data = localStorage.getItem('debug-session');
if (data) {
store.import(data);
}
}
Share Sessions with Team
// Share via URL
function shareSession() {
const snapshot = store.export();
const compressed = compressString(snapshot);
const url = `${window.location.origin}?debug=${compressed}`;
navigator.clipboard.writeText(url);
}
// Load from URL
useEffect(() => {
const params = new URLSearchParams(window.location.search);
const debugData = params.get('debug');
if (debugData) {
const decompressed = decompressString(debugData);
store.import(decompressed);
}
}, []);
Advanced Time-Travel
Conditional Time-Travel
import { getTimeTravel } from 'react-dev-debugger';
const timeTravel = getTimeTravel();
// Jump to first error state
function goToFirstError() {
const timeline = getTimeline().getEntries();
const errorIndex = timeline.findIndex(entry =>
entry.update.label === 'error'
);
if (errorIndex !== -1) {
timeTravel.goTo(errorIndex);
}
}
// Find state by value
function findState(predicate) {
const entries = getTimeline().getEntries();
const index = entries.findIndex(entry =>
predicate(entry.snapshot.state)
);
if (index !== -1) {
timeTravel.goTo(index);
}
}
Replay Mode
class ReplayController {
constructor() {
this.timeTravel = getTimeTravel();
this.isPlaying = false;
this.speed = 1000; // ms per step
}
play() {
this.isPlaying = true;
this.playNext();
}
playNext() {
if (!this.isPlaying) return;
if (this.timeTravel.canStepForward()) {
this.timeTravel.stepForward();
setTimeout(() => this.playNext(), this.speed);
} else {
this.stop();
}
}
stop() {
this.isPlaying = false;
}
setSpeed(ms) {
this.speed = ms;
}
}
Graph Analysis
Query Dependencies
import { getDependencyGraph } from 'react-dev-debugger';
const graph = getDependencyGraph();
// Find all components using a specific state
function findStateConsumers(stateId) {
const edges = graph.getEdges();
return edges
.filter(edge => edge.from === stateId)
.map(edge => graph.getNode(edge.to));
}
// Find circular dependencies
function findCircularDeps() {
const visited = new Set();
const recursionStack = new Set();
function hasCycle(nodeId) {
visited.add(nodeId);
recursionStack.add(nodeId);
const edges = graph.getEdges().filter(e => e.from === nodeId);
for (const edge of edges) {
if (!visited.has(edge.to)) {
if (hasCycle(edge.to)) return true;
} else if (recursionStack.has(edge.to)) {
return true;
}
}
recursionStack.delete(nodeId);
return false;
}
return graph.getNodes().some(node => hasCycle(node.id));
}
Component Hierarchy
// Build component tree
function buildComponentTree() {
const components = graph.getNodes().filter(n => n.type === 'component');
const tree = {};
components.forEach(comp => {
if (!comp.parentId) {
tree[comp.id] = buildSubtree(comp.id);
}
});
return tree;
}
function buildSubtree(parentId) {
const children = graph
.getNodes()
.filter(n => n.parentId === parentId);
return {
...graph.getNode(parentId),
children: children.map(child => buildSubtree(child.id)),
};
}
Custom Visualizations
Create Custom Views
import { useEffect, useState } from 'react';
import { getStateTracker } from 'react-dev-debugger';
function CustomDebugView() {
const [updates, setUpdates] = useState([]);
useEffect(() => {
const tracker = getStateTracker();
const unsubscribe = tracker.subscribe((update) => {
setUpdates(prev => [...prev, update]);
});
return unsubscribe;
}, []);
// Custom visualization logic
return (
<div>
<h2>Custom Debug View</h2>
{updates.map(update => (
<CustomUpdateCard key={update.id} update={update} />
))}
</div>
);
}
D3.js Integration
import * as d3 from 'd3';
import { getDependencyGraph } from 'react-dev-debugger';
function GraphVisualization() {
const svgRef = useRef();
useEffect(() => {
const graph = getDependencyGraph();
const nodes = graph.getNodes();
const edges = graph.getEdges();
// D3 force simulation
const simulation = d3.forceSimulation(nodes)
.force('link', d3.forceLink(edges).id(d => d.id))
.force('charge', d3.forceManyBody().strength(-300))
.force('center', d3.forceCenter(400, 300));
// Render with D3
const svg = d3.select(svgRef.current);
// ... D3 rendering code
}, []);
return <svg ref={svgRef} width={800} height={600} />;
}
Performance Profiling
Advanced Metrics
import { getRenderTracker } from 'react-dev-debugger';
const renderTracker = getRenderTracker();
// Get detailed metrics
function getPerformanceReport() {
const components = renderTracker.getAllComponents();
return components.map(comp => ({
name: comp.name,
totalRenders: comp.renderCount,
avgDuration: comp.averageRenderDuration,
maxDuration: comp.maxRenderDuration,
minDuration: comp.minRenderDuration,
totalTime: comp.totalRenderTime,
slowRenders: comp.slowRenderCount,
}))
.sort((a, b) => b.totalTime - a.totalTime);
}
// Identify bottlenecks
function findBottlenecks(threshold = 16) {
return getPerformanceReport()
.filter(comp => comp.avgDuration > threshold);
}
Flamegraph Data
// Generate flamegraph-compatible data
function generateFlamegraphData() {
const tracker = getRenderTracker();
const timeline = getTimeline().getEntries();
return timeline.map(entry => ({
name: entry.update.componentName,
value: entry.renderDuration,
timestamp: entry.timestamp,
}));
}
Testing Integration
Snapshot Testing
import { getSnapshotStore } from 'react-dev-debugger';
describe('State Management', () => {
it('should match state snapshot', () => {
const store = getSnapshotStore();
const snapshot = store.get(store.getAll().length - 1);
expect(snapshot).toMatchSnapshot();
});
});
Deterministic Replay
// Record test session
beforeAll(() => {
recordSession();
});
afterAll(() => {
const session = stopRecording();
saveSessionToFile(session);
});
// Replay in tests
it('should reproduce bug', () => {
const session = loadSessionFromFile();
replaySession(session);
// Assert expected state
expect(getAppState()).toBe(expectedState);
});
Plugin System
Create Custom Plugins
class DebugPlugin {
constructor(name, options) {
this.name = name;
this.options = options;
this.tracker = getStateTracker();
}
init() {
this.unsubscribe = this.tracker.subscribe(this.onUpdate.bind(this));
}
onUpdate(update) {
// Plugin logic
}
destroy() {
this.unsubscribe?.();
}
}
// Usage
const plugin = new DebugPlugin('MyPlugin', { /* options */ });
plugin.init();
Logger Plugin Example
class LoggerPlugin extends DebugPlugin {
onUpdate(update) {
console.group(`[${update.componentName}] ${update.label}`);
console.log('Previous:', update.prevValue);
console.log('Next:', update.nextValue);
console.groupEnd();
}
}
WebSocket Sync
Remote Debugging
import { getStateTracker } from 'react-dev-debugger';
class RemoteDebugger {
constructor(wsUrl) {
this.ws = new WebSocket(wsUrl);
this.tracker = getStateTracker();
this.setupSync();
}
setupSync() {
this.tracker.subscribe((update) => {
this.ws.send(JSON.stringify({
type: 'STATE_UPDATE',
data: update,
}));
});
this.ws.onmessage = (event) => {
const message = JSON.parse(event.data);
if (message.type === 'TIME_TRAVEL') {
getTimeTravel().goTo(message.index);
}
};
}
}