skip to content

React exposes useInsertionEffect alongside useEffect and useLayoutEffect. When does it fire relative to the other two, who is it intended for, and what can you not do inside it?

level: seniorimportance: nice to knowfreq 18%

answer

  1. earliest of the three effect slots
  2. think generated stylesheet rules
  3. styles must precede any measurement
  4. no refs, no state updates there
  5. library authors only

basics

~20 s

useInsertionEffect fires before any layout effects, which lets a CSS-in-JS library inject style rules early enough that layout effects and the browser see them. It is for library authors: refs are not attached yet and you cannot update state inside it.

solid answer

~40 s

It is the earliest of the three effect hooks in a commit: React runs insertion effects before any layout effects, which is the entire point. A CSS-in-JS library needs its generated `<style>` rules in the document before anything reads layout, otherwise every measurement in a layout effect is taken against unstyled elements and the numbers are wrong. Because it runs that early, React restricts it — refs are not attached yet, you cannot schedule a state update from it, and React documents that you should not rely on the DOM having been updated when it runs. Like the other effect hooks it does not run during server rendering. Application code should essentially never call it; if you are reaching for it in product code, the answer you want is almost always `useLayoutEffect`.

go deeper

for a junior

Just place it correctly: it is the earliest of React's three effect hooks and exists for CSS-in-JS libraries, not for application code. Saying you would use useEffect or useLayoutEffect instead is the right instinct here.

for a middle

Explain the ordering — insertion effects before layout effects before paint — and why style rules must land before anything reads layout, otherwise measurements are taken against unstyled elements.

for a senior

Name the restrictions and tie each to the timing: refs are not attached yet, state updates are not allowed, it does not run on the server, and the DOM is not guaranteed to be updated. Then say plainly that product code should not call it.

for a principal

Frame it as an API-boundary decision: React added a narrow slot with hard restrictions rather than loosening layout effects for everyone. Be ready to discuss when a runtime style-injection library is worth its cost at all, given build-time alternatives.

## The problem it exists to solve A runtime CSS-in-JS library generates class names during render and must get the matching rules into the document. If it inserts them too late, two things go wrong. Layout effects that measure elements do so before the styles apply, so every measurement is taken against the wrong box. And inserting rules while the browser is in the middle of laying things out forces extra style recalculation on the critical path. `useInsertionEffect` gives those libraries a slot that is early enough: React runs insertion effects **before any layout effects** in the commit. By the time a layout effect runs and reads the DOM, the rules that library injected are already in the document. ```js // inside a CSS-in-JS library, not in product code useInsertionEffect(() => { if (!isInserted(rule)) insertStyleRule(rule); }); ``` ## Ordering, stated carefully The fact worth memorising is the relative one: insertion effects run before layout effects, and layout effects run before the browser paints, and passive effects (`useEffect`) run after. What React deliberately does **not** promise is that the DOM has already been updated when an insertion effect runs — the documentation says it may run either before or after the DOM mutation, so you must not write code inside it that depends on the committed DOM being in place. That is a restriction, not an implementation detail to work around; it is what keeps React free to schedule the slot as it needs to. ## What React forbids inside it The hook is deliberately narrow: - **Refs are not attached yet.** Anything you would reach for a DOM node with is unavailable, which is another reason it is the wrong tool for measurement. - **You cannot update state.** Calling a setter from an insertion effect is not supported; the slot exists to write into the document, not to drive a re-render. - **It does not run on the server.** Like every effect, it belongs to the commit, and a server render never commits — so a library still needs a separate path for collecting styles during server rendering. Those limits fall straight out of *when* it runs: too early for refs, too early to be a place where React re-enters rendering. ## Why product code should not use it Interviewers ask about this hook to see whether you can place a rarely used API correctly rather than to see you use it. The honest answer is that application components have no business calling it. If you need to run something before the user sees the frame, that is `useLayoutEffect`. If you need it after, that is `useEffect`. The only reason `useInsertionEffect` was added is that style injection has a hard ordering requirement relative to layout reads that neither of the other two could satisfy, and only a library that owns style injection has that requirement. A good answer therefore has three parts: it fires before layout effects; it exists so injected styles are present before anything measures; and its restrictions (no refs, no state updates, no server run, no guaranteed DOM) mark it as library-only. If you cannot recall the restrictions, say confidently that it is a CSS-in-JS hook that runs earlier than `useLayoutEffect` and that you would not put it in application code — that is a stronger answer than inventing capabilities it does not have.

  • Why can a CSS-in-JS library not simply inject its rules from useLayoutEffect?
    Because layout effects across the tree all run in the same phase, and a component's own layout effect may measure elements before the library's layout effect has inserted the rules — the measurement would then be taken against unstyled boxes. `useInsertionEffect` runs before every layout effect, which removes that ordering hazard entirely.
  • If useInsertionEffect runs earliest, why not use it for a fast pre-paint DOM correction?
    Because refs are not attached yet, so you have no node to correct, you cannot trigger a state update from it, and React explicitly does not guarantee the DOM has been updated when it runs. Pre-paint DOM work is what `useLayoutEffect` is for; that hook runs after mutation with refs attached.
  • Does useInsertionEffect help a CSS-in-JS library during server rendering?
    No. Like every effect it belongs to the commit phase, and a server render never commits, so it does not run. Libraries collect the styles they generate during the render pass itself and emit them into the server HTML through a separate mechanism; the hook only covers the client.

saying these in an interview costs you the question

  • It is a faster alternative to useLayoutEffect for any DOM work
  • Refs are already attached inside useInsertionEffect
  • You can set state from it to trigger a re-render
  • It runs on the server so styles ship in the HTML
  • Application components should use it for style changes

context