How to Update useInsertionEffect in React
This article provides a straightforward guide on how to work with and
update the useInsertionEffect hook in React. You will learn
its specific use case for injection of dynamic styles, how to trigger
updates using the dependency array, and the best practices for managing
style cleanups to prevent memory leaks and layout thrashing.
Understanding useInsertionEffect
The useInsertionEffect hook is a specialized version of
useEffect introduced in React 18. It runs synchronously
before any layout effects (useLayoutEffect) and
before the browser paints the screen.
This hook is designed strictly for CSS-in-JS library authors to
inject <style> tags into the document head
dynamically. Because it runs before layout effects, it ensures that the
browser has the correct styles computed before it calculates the layout,
avoiding performance bottlenecks.
How to Update useInsertionEffect
To update the styles injected by useInsertionEffect, you
utilize its dependency array and a cleanup
function, similar to how you manage updates in
useEffect. When a dependency changes, React runs the
cleanup function to remove the old styles and then executes the effect
again to insert the updated styles.
Here is the step-by-step implementation:
1. Define the Hook with Dependencies
Pass the variables that dictate your styles (such as a theme or color) into the dependency array at the end of the hook.
2. Implement a Cleanup Function
Always return a cleanup function inside
useInsertionEffect to remove the injected
<style> tag from the document head. This prevents
duplicate style rules from piling up in the DOM when updates occur.
Code Example: Updating Dynamic Styles
import { useInsertionEffect, useState } from 'react';
// Custom hook to insert and update dynamic styles
function useDynamicTheme(themeColor) {
useInsertionEffect(() => {
// 1. Create the style element
const styleTag = document.createElement('style');
styleTag.textContent = `
.dynamic-button {
background-color: ${themeColor};
color: white;
padding: 10px 20px;
border: none;
border-radius: 4px;
}
`;
// 2. Insert the style into the document head
document.head.appendChild(styleTag);
// 3. Cleanup: Remove the old style tag when themeColor changes
return () => {
document.head.removeChild(styleTag);
};
}, [themeColor]); // React tracks this dependency to trigger updates
}
export default function App() {
const [color, setColor] = useState('blue');
// The hook will update whenever the "color" state changes
useDynamicTheme(color);
return (
<div>
<button className="dynamic-button">Styled Button</button>
<button onClick={() => setColor('red')}>Change to Red</button>
<button onClick={() => setColor('green')}>Change to Green</button>
</div>
);
}Important Rules and Limitations
When updating or using useInsertionEffect, keep the
following constraints in mind:
- No State Updates: Do not attempt to update React
state inside
useInsertionEffect. Doing so can cause rendering loops and timing issues. - No Access to Refs: You cannot access DOM refs inside this hook because the DOM nodes have not yet been laid out or painted when this effect runs.
- Client-Only: This hook does not run during Server-Side Rendering (SSR). It only executes on the client.
- Use Sparingly: If you are not building a CSS-in-JS
library, use standard
useEffectoruseLayoutEffectinstead. Regular application code rarely needsuseInsertionEffect.