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​