skip to content

Effects and Lifecycle

How a React component reaches outside itself — running side effects, subscribing to external systems, touching real DOM nodes, and cleaning up after itself. Effects are where most real-world React bugs live, so interviewers use them to find out whether you actually think declaratively or are still writing lifecycle code in hook syntax.

part ofReactoverview, primer and where to startread it →
on this pageshow

explore

questions

62 · 6 sections

In React, what is the difference between calling useEffect(fn) with no second argument, useEffect(fn, []), and useEffect(fn, [a, b])?

level: juniorimportance: must knowfreq 80%
basics
~20 s

Omitting the second argument runs the effect after every render. An empty array runs it once after mount, with cleanup at unmount. A list of values re-runs it whenever any listed value changes, compared with Object.is.

open as a page

In a React component, a Buy button must POST an order and then show a confirmation toast. One version does both inside the onClick handler; another sets `ordered` state in the handler and runs `useEffect(() => { if (ordered) { postOrder(); showToast(); } }, [ordered])`. Which is correct, and why?

level: juniorimportance: must knowfreq 68%
basics
~20 s

Both belong in the onClick handler: they are caused by a specific user action, not by the component being displayed. Routing them through state and an effect adds a render pass, an extra state field, and a path for the request to fire twice.

open as a page

In a React component you subscribe to a media query with window.matchMedia('(max-width: 600px)') inside useEffect. What must that effect return, and what goes wrong in an app that mounts and unmounts that component many times if it doesn't?

level: juniorimportance: must knowfreq 65%
basics
~20 s

The effect must return a cleanup function that removes the exact listener it added. Without it, every mount leaves another live listener on the MediaQueryList, so subscriptions pile up, unmounted components keep reacting, and the retained closures leak memory.

open as a page

In React, when you return a function from the callback you pass to useEffect, what does React do with that function and when does it call it?

level: juniorimportance: must knowfreq 80%
basics
~20 s

React treats the returned function as that effect's cleanup. It calls the cleanup before running the effect again after a dependency change, and once more when the component unmounts, so every setup is torn down exactly once.

open as a page

How does React decide whether to re-run a useEffect between renders, and why does a dependency like useEffect(fn, [{ page: 1 }]) make the effect run after every single render?

level: middleimportance: must knowfreq 63%
basics
~20 s

React compares each dependency with the previous render's value using Object.is, position by position. An object, array or function created in the component body is a new reference on every render, so Object.is always reports a change and the effect re-runs each time.

open as a page

In React, a component polls by calling setInterval inside a useEffect. What must that effect return, and what goes wrong on a screen the user opens and leaves repeatedly?

level: juniorimportance: must knowfreq 62%
basics
~20 s

The effect must return a cleanup function that calls clearInterval with the id setInterval returned. Without it, every mount leaves another live timer behind, so abandoned components keep polling forever and traffic multiplies with each visit.

open as a page

A React component loads its data by calling `fetch` inside `useEffect` and storing the result with `useState`. Why does that component always render at least once with no data, and what does that force you to write by hand?

level: juniorimportance: must knowfreq 72%
basics
~10 s

Effects run after React has rendered and committed the component, so the first render happens before the request is even sent. Every fetch-in-effect component therefore needs hand-written loading, error and empty states.

open as a page

In React, how do you wire an AbortController into a useEffect that calls fetch, and why must the controller be created inside the effect body rather than held in a ref?

level: middleimportance: must knowfreq 68%
basics
~20 s

Create a fresh AbortController inside the effect body, pass controller.signal as fetch's signal option, and return a cleanup that calls controller.abort(). A controller is single-use: once aborted its signal stays aborted, so a shared one poisons every later request.

open as a page

In a React client app, `<Dashboard>` fetches the current user in a `useEffect` and renders `<Projects>` only once that user has arrived; `<Projects>` then fetches in its own `useEffect`. Why do the two requests run one after the other instead of in parallel, and how would you remove that waterfall?

level: middleimportance: must knowfreq 62%
basics
~20 s

The child is not mounted until the parent's data arrives, so its effect is never scheduled and its request cannot start. Each nesting level adds a full round trip. Removing it means starting both requests from one place instead of gating one render on the other.

open as a page

A React component fetches inside an effect: useEffect(() => { fetch('/api/users/' + userId).then(r => r.json()).then(setUser); }, [userId]). When the user switches userId from 1 to 2 quickly, the page sometimes ends up showing user 1's data. Why does that happen, and how do you fix it inside the effect?

level: middleimportance: must knowfreq 72%
basics
~20 s

Two fetches for different ids can resolve in the wrong order, so the older response's state update overwrites the newer data. Fix it with an ignore flag declared inside the effect, set to true in its cleanup, that guards every state write.

open as a page

In React, why is ref.current still null while a component is rendering, and at what point does React actually set it to the DOM node?

level: middleimportance: must knowfreq 72%
basics
~20 s

React attaches DOM refs during the commit phase, after the rendered output is applied to the DOM. While a component renders, the node does not exist yet, so ref.current is still the initial value (null on first render). Read it in effects or event handlers.

open as a page

How would you integrate a third-party library that creates and owns its own DOM — a charting library, a map, a rich-text editor — into a React function component?

level: middleimportance: must knowfreq 60%
basics
~20 s

Render an empty container element with a ref, create the library instance in an effect from that node, keep the instance in a ref, and destroy it in the effect's cleanup. React renders no children inside that container.

open as a page

A React tooltip renders at a default position, then reads the trigger's getBoundingClientRect() inside a useEffect and calls setState to move it. Users see the tooltip flash in the wrong place for one frame. Why does that happen, and what do you change?

level: middleimportance: must knowfreq 68%
basics
~20 s

useEffect runs after the browser has painted, so the unmeasured position is visible for one frame. Move the measure-and-reposition work into useLayoutEffect, which React runs synchronously after it mutates the DOM and before the browser paints.

open as a page

In React, what is a callback ref, and what does React pass to that function when the element mounts and when it unmounts?

level: juniorimportance: should knowfreq 52%
basics
~20 s

A callback ref is a function passed as an element's ref prop instead of a ref object. React calls it with the DOM node when the element attaches, and with null when it detaches, so you can run code at the exact moment a node appears or disappears.

open as a page

A teammate wraps a charting library in a React function component by calling `new Chart(document.getElementById('chart'), config)` directly in the component body, above the returned JSX. What is wrong with initializing it there?

level: juniorimportance: should knowfreq 45%
basics
~20 s

Component bodies must stay pure. That call runs again on every render, targets a node React has not created yet on the first render, and a document lookup collides across instances. Initialize in an effect against a ref instead.

open as a page

In a React 19 app, a component's useEffect with an empty dependency array runs twice when the component first mounts in development, but only once in the production build. What causes that, and what is it there for?

level: juniorimportance: must knowfreq 78%
basics
~20 s

React's <StrictMode> deliberately mounts each component an extra time in development, running setup, then cleanup, then setup again, so effects that never clean up break loudly. It is development-only; production mounts and runs the effect once.

open as a page

In a React app, a developer stops an effect from running twice under <StrictMode> by adding `const didRun = useRef(false)` and returning early when it is already true. Why do reviewers treat that as a red flag, and what should be done instead?

level: middleimportance: must knowfreq 62%
basics
~20 s

The ref guard suppresses the warning, not the defect. StrictMode's second run only revealed that the effect never undoes its own setup, and that leak still happens on any real remount in production. The fix is to write the cleanup.

open as a page

Beyond re-running effects, what else does React's <StrictMode> deliberately invoke twice during a development render, and what kind of bug is that designed to expose?

level: middleimportance: should knowfreq 45%
basics
~20 s

StrictMode also double-invokes the functions React expects to be pure: the component body itself, the initializer function passed to useState, and state updater functions. Running each twice makes impure code — mutation or side effects during render — produce visibly wrong results.

open as a page

After enabling <StrictMode> in a React app, an analytics 'page_view' event sent from a mount effect starts firing twice in development. How do you decide whether that is a real defect, and what do you change?

level: seniorimportance: should knowfreq 38%
basics
~20 s

Ask whether a genuine unmount and remount would also double the event. It would, so this is a real defect that development merely surfaced early. Fix it by moving the send to the interaction that causes it, or by making the operation deduplicate outside the component.

open as a page

You are leading an upgrade of a large React codebase where <StrictMode> has never been enabled, and turning it on at the root produces hundreds of duplicated effects and console warnings. How do you decide whether and how to adopt it?

level: principalimportance: nice to knowfreq 20%
basics
~20 s

Adopt it, but incrementally. <StrictMode> wraps any subtree, not only the root, so enable it around areas as they are cleaned up and expand outward. Treat the noise as a backlog of real cleanup defects, triaged by whether a genuine remount would break the same code.

open as a page

In React, what does an error boundary do, and what happens when a component throws during render and there is no error boundary above it?

level: juniorimportance: must knowfreq 72%
basics
~20 s

An error boundary catches an error thrown while rendering anywhere in its subtree and shows fallback UI instead of that subtree. With no boundary above the throwing component, React unmounts the entire tree and the page goes blank.

open as a page

Which failures does a React error boundary NOT catch, and how do you get those errors in front of a boundary anyway?

level: middleimportance: must knowfreq 62%
basics
~20 s

React error boundaries only catch errors React itself throws while rendering, in constructors, in lifecycle methods, and in effects. They miss event handlers, asynchronous callbacks, server rendering, and the boundary's own errors. The fix is to catch such errors and rethrow them during render.

open as a page

In a React class error boundary, what is the difference between static getDerivedStateFromError(error) and componentDidCatch(error, errorInfo), and what belongs in each?

level: middleimportance: must knowfreq 66%
basics
~20 s

getDerivedStateFromError is a static, pure, render-phase method that returns a state patch so the boundary renders its fallback. componentDidCatch runs after the commit and is where side effects such as logging belong. Most boundaries implement both.

open as a page

React 19 still ships no built-in hook for creating an error boundary. Why must a boundary be a class component, and how do hooks-only codebases deal with that?

level: middleimportance: should knowfreq 44%
basics
~20 s

React exposes error catching only through the class methods getDerivedStateFromError and componentDidCatch; no hook equivalent exists in React 19. Teams write one small boundary class and reuse it, or adopt the react-error-boundary package, which wraps that class in a hook-friendly API.

open as a page

A React error boundary is showing its fallback and the user clicks "Try again". What has to happen for the subtree to genuinely recover, and why does merely clearing the boundary's error state often fail?

level: seniorimportance: should knowfreq 46%
basics
~20 s

Recovery needs two steps: clear the boundary's error state so children render again, and clear whatever caused the failure. Clearing only the error re-renders the same inputs, so the component throws immediately and the fallback returns — often in a tight loop.

open as a page

In React, how do the class lifecycle methods componentDidMount, componentDidUpdate and componentWillUnmount map onto useEffect, and where does that mapping mislead you?

level: middleimportance: must knowfreq 74%
basics
~20 s

useEffect with empty dependencies approximates componentDidMount, its returned cleanup approximates componentWillUnmount, and non-empty dependencies approximate componentDidUpdate. The mapping misleads because one effect covers all three, and cleanup runs before every re-run, not only at unmount.

open as a page

You are reading an older React class component and find a method named UNSAFE_componentWillReceiveProps. What does the UNSAFE_ prefix mean, and what should the code use instead?

level: juniorimportance: should knowfreq 36%
basics
~20 s

UNSAFE_ marks a legacy render-phase lifecycle, not a security problem. React may pause, abandon and restart a render, so these methods can run more than once or for work that is thrown away. The safe replacements are the commit-phase methods and getDerivedStateFromProps.

open as a page

In a React class component, what is static getDerivedStateFromProps(props, state) called with, when does it run, and what is the function-component equivalent?

level: middleimportance: should knowfreq 42%
basics
~20 s

It is a static method receiving the next props and current state, called before every render — on mount and on every update, whatever triggered it. It returns an object merged into state, or null. Function components have no direct equivalent: derive during render instead.

open as a page

In React, how does React.memo relate to a class component's shouldComponentUpdate and to React.PureComponent, and what can the class APIs do that memo cannot?

level: middleimportance: should knowfreq 54%
basics
~20 s

React.memo is the function-component counterpart of PureComponent: it shallow-compares props and skips the re-render if they match. PureComponent also shallow-compares state, and shouldComponentUpdate can compare anything — memo sees props only, and its comparator's return value is inverted.

open as a page

After migrating a React class to a function component, a popover's measuring code that used to run in this.setState({ open: true }, () => this.measure()) now measures the old layout. Why, and how do you restore the ordering?

level: seniorimportance: should knowfreq 38%
basics
~20 s

State setters in function components take no callback, so calling measure() right after setOpen(true) runs before React re-renders and commits — it measures the previous DOM. Move the measurement into a useLayoutEffect that depends on the state value.

open as a page