Engrain by ByteRush

RCT.03.06 Mid-level· 11 minCore — asked often

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);
This example uses Node.js, so it runs in our checks rather than in your browser.

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
Render, insertion, layout, paint, effectStep 1 of 4

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
    1. Render: React calls both EmailField components. Each useId returns its own id, stable across server and client.
    2. Commit: DOM nodes are inserted. Insertion effects run first, for libraries that inject style tags.
    3. Layout effects run before the browser paints, so measuring and adjusting here never flickers.
    4. 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?

    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.”

    Stays on your device. Nothing is uploaded.
    Follow-up What is the difference between useEffect and useLayoutEffect?
    The first runs after paint and does not block it. The layout one runs before paint and blocks it, for measurements that must not flicker.
    Follow-up What is useId for?
    Stable, unique ids for accessibility attributes (htmlFor, aria-describedby) that match between server and client rendering.
    Follow-up Can useId be used as a list key?
    No. Keys must come from your data; useId identifies a component instance, not an item.

    Practice#

    Guided

    Write the store behind a useOnlineStatus hook, using the three functions useSyncExternalStore needs.

    Done when

    • subscribe listens to both online and offline events and the unsubscribe removes both.
    • getSnapshot reads navigator.onLine from the given window.
    • getServerSnapshot returns true.
    Your solution
    Ctrl/⌘ + Enter

    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
    The hook 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
    An effect event, 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 useEffect and useLayoutEffect?
    • What is useId for?