Skip to main content

Performance Optimization

Learn how to optimize React Dev Debugger for better performance in large applications.

Best Practices

1. Limit Snapshot History

Control the number of snapshots stored in memory:

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

const store = getSnapshotStore();

// Configure max snapshots (default: 100)
store.setMaxSnapshots(50);

For adapters:

createReduxAdapter(store, {
maxSnapshots: 50,
});

2. Filter Frequent Updates

Skip tracking high-frequency state updates:

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

const tracker = getStateTracker();

// Add a filter
tracker.setFilter((update) => {
// Skip mouse position updates
if (update.label === 'mousePosition') return false;

// Skip animation frame updates
if (update.componentName === 'AnimationController') return false;

return true;
});

3. Use Debug Labels Wisely

Meaningful labels help, but don't overdo it:

// ✅ Good
const [user, setUser] = useTrackedState(null, 'currentUser');
const [cart, setCart] = useTrackedState([], 'shoppingCart');

// ❌ Too verbose
const [x, setX] = useTrackedState(0, 'mousePositionXCoordinate');

4. Disable in Production

The debugger automatically disables in production, but you can force it:

// Only import in development
if (process.env.NODE_ENV === 'development') {
import('react-dev-debugger/dev');
}

5. Selective Component Tracking

Only track specific components:

function ExpensiveComponent({ data }) {
// Only track in development
if (process.env.NODE_ENV === 'development') {
useRenderTracking('ExpensiveComponent');
}

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

Performance Monitoring

Track Slow Renders

Use the built-in performance tracking:

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

function DataTable({ data }) {
const metrics = useRenderTracking('DataTable', 16); // 16ms threshold

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

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

Identify Unnecessary Re-renders

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

function OptimizedComponent(props) {
useWhyDidYouUpdate('OptimizedComponent', props);

// Check console for which props changed
return <div>{/* ... */}</div>;
}

Memory Management

Clear Old Data

Periodically clear snapshot history:

import { getSnapshotStore, getTimeline } from 'react-dev-debugger';

// Clear all history
function clearDebugHistory() {
getSnapshotStore().clear();
getTimeline().clear();
}

// Clear automatically after 1000 updates
let updateCount = 0;
tracker.subscribe(() => {
updateCount++;
if (updateCount > 1000) {
clearDebugHistory();
updateCount = 0;
}
});

Throttle Updates

For high-frequency updates, use throttling:

import { throttle } from 'lodash';

function MouseTracker() {
const [position, setPosition] = useTrackedState({ x: 0, y: 0 }, 'mouse');

// Throttle updates to 100ms
const updatePosition = throttle((x, y) => {
setPosition({ x, y });
}, 100);

return (
<div onMouseMove={(e) => updatePosition(e.clientX, e.clientY)}>
{/* ... */}
</div>
);
}

Bundle Size Optimization

Code Splitting

Only load the debugger when needed:

// Lazy load debugger
const loadDebugger = async () => {
if (process.env.NODE_ENV === 'development') {
await import('react-dev-debugger/dev');
}
};

// Load on demand
document.addEventListener('keydown', (e) => {
if (e.ctrlKey && e.shiftKey && e.key === 'D') {
loadDebugger();
}
});

Tree Shaking

Ensure your bundler can tree-shake unused features:

// Only import what you need
import { useTrackedState } from 'react-dev-debugger';

// Instead of
import * as Debugger from 'react-dev-debugger';

Adapter-Specific Optimization

Redux

createReduxAdapter(store, {
// Filter frequent actions
actionFilter: (action) => {
const ignored = ['@@redux/INIT', 'persist/'];
return !ignored.some(prefix => action.type.startsWith(prefix));
},

// Simplify large state
stateTransform: (state) => ({
user: state.user.id,
items: state.items.length,
// ... simplified version
}),
});

Zustand

createZustandAdapter(useStore, {
// Only track specific slices
trackSlices: ['user', 'cart'],
maxSnapshots: 30,
});

Production Considerations

Disable Completely

Remove debugger from production builds:

// webpack.config.js
module.exports = {
resolve: {
alias: {
'react-dev-debugger':
process.env.NODE_ENV === 'production'
? 'react-dev-debugger/noop'
: 'react-dev-debugger',
},
},
};

Environment Variables

# .env.development
REACT_APP_ENABLE_DEBUGGER=true

# .env.production
REACT_APP_ENABLE_DEBUGGER=false
if (process.env.REACT_APP_ENABLE_DEBUGGER === 'true') {
import('react-dev-debugger/dev');
}

Benchmarking

Measure Impact

const start = performance.now();

// Your code with debugger
const [state, setState] = useTrackedState(0, 'counter');

const end = performance.now();
console.log(`Hook overhead: ${end - start}ms`);

Compare Performance

// Without debugger
const baseline = measureRenderTime(ComponentWithoutDebugger);

// With debugger
const withDebugger = measureRenderTime(ComponentWithDebugger);

console.log(`Overhead: ${withDebugger - baseline}ms`);

Tips for Large Applications

  1. Use Selective Tracking - Only track critical state
  2. Limit History - Set reasonable maxSnapshots
  3. Filter Noise - Skip frequent, unimportant updates
  4. Clear Regularly - Don't let history grow indefinitely
  5. Lazy Load - Only activate debugger when needed
  6. Monitor Memory - Watch browser DevTools memory tab

Performance Checklist

  • maxSnapshots configured appropriately
  • Filters set up for noisy updates
  • Debug labels are concise
  • Production builds exclude debugger
  • Large state objects are transformed
  • High-frequency updates are throttled
  • Memory usage is monitored
  • Only critical components tracked

Next Steps