Skip to solution
easyFrontend

How do you handle side effects in functional components?

971 views
01

Understand the problem

Question presented to candidate: "Your component needs to fetch data, subscribe to a websocket, and start a timer. Where does that code go, and why can it not just live in the component body?"

What a strong answer should cover:

  • What counts as a side effect: anything reaching outside the component's own render output — network, subscriptions, timers, manual DOM work, logging.
  • Render must stay pure; effects are deliberately pushed out of it.
  • useEffect runs after render and after the browser paints; the dependency array controls re-runs.
  • The cleanup function runs before the next effect run and again on unmount — never after.
  • The cancellation-flag pattern for data fetching, and why it prevents a stale response overwriting fresh state.
  • useLayoutEffect as the narrow synchronous exception, not a default.
  • Effects do not run during server-side rendering.
  • Modern framing: effects are for synchronising with external systems, not for deriving state.

Clarifying questions expected:

  • "Is this app server-rendered?" — it changes whether an effect can be relied on for first paint.
  • "Are we on React 19? Can I use use() and Suspense instead of a fetch effect?"

Code / implementation expected: Yes — a useEffect with a dependency array and a cleanup function. The data-fetching variant with a cancellation flag is the strongest version.

hooksuseeffectside effectsdata fetching
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: Frontend engineers preparing for React interviews — assumes basic familiarity with Hooks. Difficulty: Medium

How to read this doc: Every concept is explained in plain language first, then tagged with 📌 Interview term: — the exact vocabulary an interviewer expects. Every ord

Solution ready — 2 min read

Classified // press E to declassify

04

Explore the playground snippets

Effect with cleanup, plus the cancellation-flag fetch pattern
Run Playground
import { useState, useEffect } from "react";

// Stands in for a real API. Deliberately slow for low ids so you can watch a
// stale response get discarded instead of overwriting a newer one.
function fetchUser(id) {
  const delay = id === 1 ? 1500 : 300;
  return new Promise((resolve) =>
    setTimeout(() => resolve({ id, name: `User #${id}` }), delay),
  );
}

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);

  useEffect(() => {
    let cancelled = false;
    setUser(null);

    fetchUser(userId).then((data) => {
      if (!cancelled) setUser(data); // guard against a stale response
    });

    // Runs when userId changes OR when this component unmounts — always
    // BEFORE the next effect run, which is what makes the guard work.
    return () => {
      cancelled = true;
    };
  }, [userId]);

  return <p>{user ? user.name : "Loading..."}</p>;
}

export default function App() {
  const [id, setId] = useState(1);
  const [width, setWidth] = useState(window.innerWidth);

  // A subscription effect: subscribe once, clean up on unmount.
  useEffect(() => {
    const onResize = () => setWidth(window.innerWidth);
    window.addEventListener("resize", onResize);
    return () => window.removeEventListener("resize", onResize);
  }, []);

  return (
    <div style={{ padding: 24, fontFamily: "system-ui", lineHeight: 1.6 }}>
      <UserProfile userId={id} />
      <button onClick={() => setId(1)}>Load slow user (1)</button>{" "}
      <button onClick={() => setId(2)}>Load fast user (2)</button>
      <p style={{ color: "#666", fontSize: 13 }}>
        Click 1 then immediately 2. Without the cancelled flag, the slow
        response for user 1 would land last and clobber user 2.
      </p>
      <p>Window width: <strong>{width}px</strong> — resize to see the subscription work.</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 5 of 119 decoded in the React.js track. One more won't hurt.

Back to track