Other hooks: useId, useSyncExternalStore, useLayoutEffect and useEffectEvent
The hooks you use less often but get asked about: useId for SSR-safe ids, useSyncExternalStore for browser and store subscriptions, useLayoutEffect vs useEffect, useInsertionEffect, useDebugValue and useEffectEvent.
Comes up in: React
Learn#
Deepak’s form uses id="email" for every email field. On a page with two forms, the second label focuses the first input, and screen readers announce the wrong field. With server rendering, a random id also breaks hydration.
The useId hook returns an id that is unique for each component. It is the same on the server and the client.
React runs different kinds of effects at different times after a commit. A layout effect runs before the browser paints, so you can measure the DOM and adjust it without a flicker:
import { GlobalRegistrator } from "@happy-dom/global-registrator";
GlobalRegistrator.register(); // a DOM for Node; in a browser you already have one
globalThis.IS_REACT_ACT_ENVIRONMENT = true;
const React = await import("react");
const { createElement: h, useId, useEffect, useLayoutEffect, useInsertionEffect, act } = React;
const { createRoot } = await import("react-dom/client");
const log = [];
function EmailField() {
const id = useId(); // unique, and the same on server and client
log.push("render");
useInsertionEffect(() => { log.push("insertion effect"); });
useLayoutEffect(() => { log.push("layout effect (before paint)"); });
useEffect(() => { log.push("effect (after paint)"); });
return h("div", null, h("label", { htmlFor: id }, "Email"), h("input", { id }));
}
const box = document.createElement("div");
const root = createRoot(box);
await act(() => root.render(h("div", null, h(EmailField), h(EmailField))));
console.log(log.join(" → "));
const ids = [...box.querySelectorAll("input")].map((i) => i.id);
console.log("two fields, two ids:", ids[0] !== ids[1], "| label points to input:", box.querySelector("label").htmlFor === ids[0]);
console.log("useEffectEvent available:", typeof React.useEffectEvent);Output (verified)
render → render → insertion effect → insertion effect → layout effect (before paint) → layout effect (before paint) → effect (after paint) → effect (after paint) two fields, two ids: true | label points to input: true useEffectEvent available: function
State
- field 1: id A
- field 2: id B
Console
empty
Render: React calls both EmailField components. Each useId returns its own id, stable across server and client.
Read the steps as text
- Render: React calls both EmailField components. Each useId returns its own id, stable across server and client.
- Commit: DOM nodes are inserted. Insertion effects run first, for libraries that inject style tags.
- Layout effects run before the browser paints, so measuring and adjusting here never flickers.
- The browser paints. Then normal effects run, without blocking the paint.
Predict#
Predict first
A tooltip measures its own height in useEffect and moves up if it would overflow. What might users see?
A normal effect runs after paint, so the first frame shows the old position. A layout effect runs before paint, so it can measure and move the tooltip first. Use it only for this, because it blocks painting.
Interview angle#
Say it like this — about 30 seconds
“The useEffect hook runs after the browser paints, so it does not block the screen. The layout version runs before paint. I use it to measure and adjust layout with no flicker. The useId hook makes ids for labels that match on the server and the client. The external store hook subscribes to things outside React, such as the online status. The insertion effect is for CSS-in-JS libraries. And the effect event hook, stable since React 19.2, reads the latest props inside an effect without making them dependencies.”
Follow-up What is the difference between useEffect and useLayoutEffect?
Follow-up What is useId for?
Follow-up Can useId be used as a list key?
Practice#
Guided
Write the store behind a useOnlineStatus hook, using the three functions useSyncExternalStore needs.
Done when
subscribelistens to both online and offline events and the unsubscribe removes both.getSnapshotreadsnavigator.onLinefrom the given window.getServerSnapshotreturns true.
Remember#
Try to answer each card before you open it. Then add them to your reviews.
useEffect vs useLayoutEffect timing?
useEffect after paint; useLayoutEffect before paint.
What is useId for?
Unique ids for labels and ARIA that match on server and client.
What three arguments does useSyncExternalStore take?
subscribe, getSnapshot and an optional getServerSnapshot.
Which hook reads the latest props in an effect without adding dependencies?
useEffectEvent.
Go deeper
Four layers. Stop at the one your interview needs; each ends with a quick check.
The core ideaEvery round
useInsertionEffect runs before layout effects, so CSS-in-JS libraries can insert style tags before anything measures. App code rarely needs it.useDebugValue(label) shows a label for a custom hook in React DevTools.Check yourself: Who should use useInsertionEffect?
CSS-in-JS library authors, to insert style tags before layout effects read layout.
How it works underneathSenior rounds
useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) reads an external store, such as a browser API or a state library. It re-renders when the snapshot changes, and it avoids tearing (RCT.02.03) Source: React: useSyncExternalStore.Check yourself: Why must getSnapshot return a cached value for objects?
A new object each call looks like a change and causes endless re-renders.
Edge cases and trapsWhere people slip
Layout effects do not run on the server. If the first client render depends on a measurement, render a stable fallback first. Keep layout effects short: they delay the frame.
Check yourself: What happens to useLayoutEffect during server rendering?
It does not run on the server; React warns in older versions.
In productionStaff-level answers
useEffectEvent(fn), is a function that always sees the latest props and state but is not a dependency, so a chat connection does not reconnect when the theme changes. It shipped in React 19.2 (React 19.2 added Activity and useEffectEvent, among others) Source: React: useEffectEvent.Check yourself: What problem does useEffectEvent solve?
Reading the latest value inside an effect without restarting the effect when it changes.
Finished the five steps? Mark it, and its cards join your reviews.
Last checked 2026-11-01. Spot a mistake? Use “Report an error” below — fixes are listed on the corrections page.
Interview questions this answers
- What is the difference between
useEffectanduseLayoutEffect? - What is
useIdfor?