How to Secure React Strict Mode

React Strict Mode is a powerful development tool that helps developers write resilient, secure, and future-proof code by highlighting potential vulnerabilities, memory leaks, and deprecated APIs. This article provides a straightforward guide on how to properly implement Strict Mode, manage its intentional double-rendering behavior, and secure your components against side-effect bugs.

What is React Strict Mode?

React Strict Mode is a utility component that activates additional checks and warnings for its descendants. It runs strictly in development mode and has no impact on production builds. By wrapping your application in <React.StrictMode>, you force React to flag unsafe lifecycles, legacy API usage, and unexpected side effects before they become security or performance issues in production.

Securing Code Against Double-Rendering

In React 18 and later, Strict Mode intentionally mounts, unmounts, and remounts components during development. This behavior simulates real-world production scenarios, such as a user navigating away and quickly returning, or state preservation during fast refresh.

To secure your application against issues caused by this double-rendering, you must ensure that all side effects are idempotent and properly cleaned up:

Here is an example of a secure, leak-proof useEffect implementation:

useEffect(() => {
  const controller = new AbortController();
  
  fetch('/api/data', { signal: controller.signal })
    .then(res => res.json())
    .then(data => setData(data))
    .catch(err => {
      if (err.name !== 'AbortError') {
        console.error(err);
      }
    });

  // Cleanup function cancels the request on unmount
  return () => {
    controller.abort();
  };
}, []);

Keeping Render Functions Pure

Strict Mode double-invokes constructers, render methods, and state updater functions to help you detect impure code. To secure your application’s state transitions, never perform side effects—such as modifying global variables, dispatching actions, or mutating state directly—inside the render phase. All side effects should be strictly confined to event handlers or useEffect hooks.

How to Implement Strict Mode

To secure your entire application, wrap your root component in <React.StrictMode> within your entry point file:

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

If you are migrating a large, legacy codebase, you can secure your application incrementally by wrapping specific component trees with <React.StrictMode> until the entire application is compliant and error-free.