yoklainterview sim

Frontend React Effects Lifecycle Interview Questions

75 verified Frontend React Effects Lifecycle interview questions — solve with answers, learn from explanations, test yourself in a real simulation.

Try the real simulation →

Sample questions

React Effects LifecycleDifficulty 1
In React, when does the function you pass to useEffect actually run, relative to the component's render?
  • aSynchronously during the render, before JSX is returned
  • bAfter React commits the render to the screen
  • cOnly when a parent component re-renders
  • dBefore the render function runs
Explanation:useEffect schedules its callback to run after the browser has painted the committed render — it is for work that reacts to a finished render (subscriptions, fetching, syncing with something outside React), not for computing what to render. Option (a) describes render-time logic, not an effect. Option (c) is wrong because a component's own render also schedules its own effects. Option (d) reverses the order entirely.
React Effects LifecycleDifficulty 1
useEffect(fn), useEffect(fn, []) and useEffect(fn, [a, b]) all take the same fn but behave differently. What is the correct summary?
  • aAll three run only once, right after mount
  • bThe array only affects cleanup timing, not whether the effect re-runs
  • cNo array: every render; []: only after mount; [a, b]: when a or b change
  • d[a, b] re-runs on every render where a or b exist
Explanation:The dependency array is what React compares between renders to decide whether to re-run the effect: omitted → always re-run, [] → compare against nothing, so it only runs after mount, [a, b] → re-run only when at least one listed value differs from the previous render. Cleanup timing follows the same schedule as the effect itself, so (b) is wrong, and (d) confuses 'the values exist' with 'the values changed'.
React Effects LifecycleDifficulty 1
function Ticker() {
  const [n, setN] = useState(0);

  useEffect(() => {
    console.log('effect ran');
  });

  return <button onClick={() => setN(n + 1)}>{n}</button>;
}

The button is clicked 3 times after the initial mount. How many times does 'effect ran' get logged in total?
  • a1 — array-less effects default to mount-only
  • b2 — one for mount, one for all clicks batched together
  • c3 — once per click, mount doesn't count
  • d4 — once after mount, once after each of the 3 re-renders
Explanation:Passing no dependency array at all means 'no comparison to skip anything', so the effect re-runs after every commit — the initial mount plus each of the 3 subsequent re-renders, giving 4 total. Option (a) inverts the actual rule (no array is the most frequent case, not the least). Option (c) wrongly excludes the mount, which is itself a commit.
React Effects LifecycleDifficulty 2
function Panel({ title }) {
  useEffect(() => {
    console.log('mounted with title:', title);
  }, []);

  return <h2>{title}</h2>;
}

The parent re-renders Panel three more times, each time passing a different title prop. What gets logged?
  • aOnly one line, logged once after the first mount, with the first title value
  • bFour lines, one for mount and one for each of the three prop changes
  • cThree lines, one per prop change; mount is skipped
  • dZero lines, [] disables the effect entirely
Explanation:An empty dependency array means React compares against 'nothing changed' on every subsequent render, so the effect body — including whatever value of title was captured in that first render's closure — only ever runs once, right after mount. Later prop changes do not trigger it again, so the logged title stays frozen at its initial value. Option (d) confuses 'runs once' with 'never runs'.
React Effects LifecycleDifficulty 2
function Profile({ userId }) {
  const [tab, setTab] = useState('posts');

  useEffect(() => {
    console.log('fetching user', userId);
  }, [userId]);

  return (
    <button onClick={() => setTab(tab === 'posts' ? 'about' : 'posts')}>
      {tab}
    </button>
  );
}

The user clicks the button 5 times (only tab changes, userId stays the same prop value throughout). How many times is 'fetching user' logged during those 5 clicks?
  • a5 times, any state or prop update reruns every effect
  • b0 times, effects with non-empty deps never fire again after mount
  • c0 times, userId never changes across those clicks
  • d1 time, all 5 clicks batched into one effect run
Explanation:React only re-runs an effect when a value in its own dependency array differs from the previous render; tab isn't listed, so changes to tab are irrelevant to this particular effect even though they do cause re-renders. Since userId never changes, the effect simply doesn't re-run — not because it's disabled (b is wrong) and not because of batching (d misapplies a concept that applies to state updates, not effect scheduling).
React Effects LifecycleDifficulty 2
function Room({ roomId }) {
  useEffect(() => {
    console.log('connect to', roomId);
    return () => console.log('disconnect from', roomId);
  }, [roomId]);

  return null;
}

roomId goes from 'a' to 'b' (a re-render), and later the component unmounts. In what order do the four console lines appear?
  • aconnect a, connect b, disconnect a, disconnect b
  • bconnect a, disconnect a, connect b, disconnect b
  • cconnect a, connect b, disconnect b, disconnect a
  • ddisconnect a, connect a, disconnect b, connect b
Explanation:Before React runs an effect again for a changed dependency, it first invokes the cleanup returned by the previous run — so the sequence for a changing dependency is always connect-old, cleanup-old, connect-new, and eventually cleanup-new at unmount. That gives connect a, disconnect a, connect b, disconnect b, matching (b).

Test yourself against the 2925-question Frontend bank.

Start interview