Skip to the solution
EasyFrontend7 min read

How do you handle side effects in functional components?

971 views

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.

  • hooks
  • useeffect
  • side effects
  • data fetching

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

7 min read Β· 9 sections

Try it in the playground

Open any example in the playground to run and change it.

ReactEffect with cleanup, plus the cancellation-flag fetch pattern
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>
  );
}

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 5 of 119 in React.js

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All React.js questions
Up nextEasy

What is the role of `react-dom`?

Continue