Skip to solution
hardFrontend

What are Effect Events (`useEffectEvent`) and what problem do they solve?

993 views
01

Understand the problem

Question presented to candidate: "An effect connects to a chat room and shows a notification using the current theme. Changing the theme should not reconnect. How do you express that?"

What a strong answer should cover:

  • The problem: some values an effect uses are not values it should react to. The dependency array has only one setting for both.
  • useEffectEvent splits them: code inside an Effect Event always sees the latest props and state, but the event itself is not a dependency.
  • So the effect re-runs only for genuinely reactive values, while still reading current ones.
  • The alternatives it replaces: lying to the lint rule (stale closure), or a ref updated every render (verbose, easy to misuse).
  • Constraints: only call an Effect Event from inside an effect in the same component — never pass it to another component or call it during render.
  • It is stable on React 19.2.8, exported from react (not experimental_useEffectEvent).
  • The distinction to state: props/state you should re-synchronise on are reactive; things you merely want to read at the moment something happens are non-reactive.

Clarifying questions expected:

  • "Which of these values should cause a reconnect, and which are just read at connect time?" — that question is the answer.

Code / implementation expected: Yes — the chat-room example with a reactive room and a non-reactive theme.

reacthookseffects
02

Attempt it yourself

Sketch your approach before reading the solution — that's what interviews test.

Nudge consolestandby

Stuck? Beam a request up — the console returns a conceptual nudge that guides your logic without spoiling the implementation.

03

Study the solution

Target Audience: Engineers preparing for senior React interviews — assumes effects and dependency arrays. Difficulty: Hard

How to read this doc: Concepts are explained in plain language first, then tagged with 📌 Interview term:. The re-run counts in section 3 were measured on React 19.2.8,

Solution ready — 2 min read

Classified // press E to declassify

04

Explore the playground snippets

A chat room that reconnects on the room but not on the theme
Run Playground
import { useState, useEffect, useEffectEvent } from "react";

// A fake chat service so the connections are observable.
function connect(roomId, log) {
  log("connect: " + roomId);
  return { disconnect: () => log("disconnect: " + roomId) };
}

function ChatRoom({ roomId, theme, log }) {
  // The Effect Event always sees the LATEST theme, but is not a dependency,
  // so changing the theme cannot cause a reconnect.
  const onConnected = useEffectEvent(() => {
    log("notify (theme=" + theme + "): joined " + roomId);
  });

  useEffect(() => {
    const conn = connect(roomId, log);
    onConnected();
    return () => conn.disconnect();
    // roomId only. The lint rule accepts this — onConnected is not reactive.
  }, [roomId]);

  return (
    <p style={{
      margin: "8px 0", padding: 8, borderRadius: 6,
      background: theme === "dark" ? "#222" : "#eee",
      color: theme === "dark" ? "#eee" : "#222",
    }}>
      In <strong>{roomId}</strong>, theme <strong>{theme}</strong>
    </p>
  );
}

const ROOMS = ["general", "random", "support"];

export default function App() {
  const [roomId, setRoomId] = useState("general");
  const [theme, setTheme] = useState("dark");
  const [log, setLog] = useState([]);
  const push = (line) => setLog((l) => [...l, line]);

  const connects = log.filter((l) => l.startsWith("connect")).length;

  return (
    <div style={{ padding: 24, fontFamily: "system-ui", lineHeight: 1.6 }}>
      <ChatRoom roomId={roomId} theme={theme} log={push} />

      <p>
        {ROOMS.map((r) => (
          <button key={r} onClick={() => setRoomId(r)} disabled={r === roomId} style={{ marginRight: 6 }}>
            {r}
          </button>
        ))}
        <button onClick={() => setTheme((t) => (t === "dark" ? "light" : "dark"))}>
          toggle theme
        </button>{" "}
        <button onClick={() => setLog([])}>clear</button>
      </p>

      <p style={{ fontSize: 14 }}>connections made: <strong>{connects}</strong></p>

      <pre style={{ background: "#f6f6f6", padding: 10, borderRadius: 6, fontSize: 12, maxHeight: 170, overflow: "auto" }}>
        {log.length ? log.join("\n") : "(nothing yet)"}
      </pre>

      <p style={{ color: "#666", fontSize: 13 }}>
        Toggle the theme repeatedly: the connection count does not move, but the
        panel restyles. Now switch rooms — one reconnect, and the notification
        reports the theme you currently have, not the one you started with.
      </p>
    </div>
  );
}
05

Join the discussion

Discussion (0)

Sign in to join the discussion.

No responses yet. Be the first to share what you think.

Transmission complete // awaiting log

KEEP THE
STREAK ALIVE.

Dossier 75 of 119 decoded in the React.js track. One more won't hurt.

Back to track