How to Optimize Strict Mode in React
React Strict Mode is a development-only tool that helps developers find potential bugs, memory leaks, and outdated practices by intentionally double-rendering components and double-invoking effects. While it does not affect production builds, it can sometimes cause performance lag or unexpected behavior during development if your codebase is not prepared for it. This article explains how to optimize your code to work efficiently with React Strict Mode, eliminate unnecessary re-renders, and ensure a smooth development experience.
1. Ensure Component Purity
React’s Strict Mode double-invokes constructor functions, render methods, and state updater functions to detect side effects. If your components are “impure” (meaning they modify external variables or state during the render phase), Strict Mode will expose this by causing unpredictable UI bugs.
To optimize: * Keep renders pure: Never mutate
props, state, or local variables outside the component’s scope during
render. * Keep state updates deterministic: State
updater functions (e.g., setCount(prev => prev + 1))
must not trigger side effects like API calls or manual DOM
manipulations.
2. Implement Proper Cleanup in useEffect
Strict Mode mounts, unmounts, and remounts every component to ensure that effects are properly cleaned up. If you do not clean up your effects, you will experience memory leaks and duplicate network requests during development.
To fix this, always return a cleanup function in your
useEffect hooks:
useEffect(() => {
const controller = new AbortController();
// Fetching data with an abort signal
fetch('/api/data', { signal: controller.signal })
.then(res => res.json())
.then(data => setData(data));
// Cleanup function to abort the request on unmount
return () => {
controller.abort();
};
}, []);Common cleanups include clearing intervals, unsubscribing from WebSockets, and removing event listeners.
3. Apply Strict Mode Selectively
If you are working with a large legacy application or using
third-party libraries that do not yet support Strict Mode, wrapping your
entire application in <React.StrictMode> might cause
significant performance bottlenecks or console errors.
Instead of applying it globally, wrap only specific, modern parts of your component tree:
import React from 'react';
function App() {
return (
<div>
<LegacyComponent /> {/* Excluded from Strict Mode */}
<React.StrictMode>
<NewFeatureComponent /> {/* Protected by Strict Mode */}
</React.StrictMode>
</div>
);
}This selective approach allows you to optimize new code without being forced to rewrite legacy code immediately.
4. Cache Expensive Calculations
Because Strict Mode runs renders twice, expensive calculations can
freeze the UI during development. Use the useMemo and
useCallback hooks to cache heavy computations and prevent
them from recalculating unnecessarily on the double-render.
// Avoid recalculating on every render pass
const sortedList = useMemo(() => {
return heavySortAlgorithm(items);
}, [items]);5. Measure Performance Using Production Builds
If you notice significant lag in your development environment, remember that Strict Mode checks only run in development. To get an accurate assessment of your application’s actual performance, always run performance profiles and audits (like Lighthouse or React DevTools Profiler) using a production build where Strict Mode is automatically stripped out.