What is useInsertionEffect in React?

This article provides a comprehensive guide to React’s useInsertionEffect hook, detailing its purpose, timing, and specific use cases. You will discover why this React 18 hook was introduced to solve performance issues in CSS-in-JS libraries, how it differs from useEffect and useLayoutEffect, and how to implement it correctly in your applications.

Understanding useInsertionEffect

useInsertionEffect is a specialized React hook introduced in React 18. It has the same signature as useEffect, but it fires synchronously before any DOM mutations take place. This means it executes before React calculates the layout of the page and before the browser paints the pixels to the screen.

Because it runs so early in the rendering lifecycle, it provides a safe window to insert global DOM nodes like <style> tags or SVG definitions before the rest of the layout is calculated.

The Problem It Solves

Before React 18, CSS-in-JS libraries (such as styled-components or Emotion) typically injected <style> tags into the document during the rendering phase or inside useLayoutEffect. This approach caused two major performance bottlenecks:

  1. Layout Thrashing: If style rules are inserted or modified while React is running layout effects, the browser is forced to recalculate style rules and layouts repeatedly.
  2. Reflows: Modifying active styles during layout calculation degrades rendering performance, especially in large application trees.

useInsertionEffect solves this by guaranteeing that styles are injected into the DOM before any layout effects run. By the time React and the browser calculate the physical layout of the elements, the required styles are already present, preventing costly style recalculations.

Syntax and Usage

The syntax for useInsertionEffect is identical to useEffect. It accepts a callback function and an optional dependency array.

import { useInsertionEffect } from 'react';

function useDynamicTheme(themeColor) {
  useInsertionEffect(() => {
    // Create and insert a style tag into the document head
    const styleTag = document.createElement('style');
    styleTag.textContent = `
      .dynamic-box {
        background-color: ${themeColor};
      }
    `;
    document.head.appendChild(styleTag);

    // Cleanup: remove the style tag when the component unmounts or color changes
    return () => {
      document.head.removeChild(styleTag);
    };
  }, [themeColor]);
}

Guidelines for Using useInsertionEffect

To maintain application performance and avoid bugs, follow these rules when working with useInsertionEffect: