What does this log, in order?
console.log('A');
setTimeout(() => console.log('B'), 0);
Promise.resolve().then(() => {
console.log('C');
setTimeout(() => console.log('D'), 0);
});
queueMicrotask(() => console.log('E'));
console.log('F');
- A. A F C E B D ✓
- B. A F C E D B
- C. A C E F B D
- D. A F E C B D
Correct answer: A. Sync runs first (A,F), then the microtask queue drains fully (C then E, since C was queued before E), and only then macrotasks in FIFO order (B, then D which was queued during the first microtask).
A senior sees this render slow. The list has 5,000 rows and a colleague immediately wraps every row in React.memo and adds useMemo everywhere. What is the correct first objection?
function Row({ item }) { return <li>{item.label}</li>; }
function List({ items }) { return <ul>{items.map(i => <Row key={i.id} item={i} />)}</ul>; }
- A. React.memo will not help because Row has no props
- B. Without profiling you don't know memo is the bottleneck; rendering 5,000 DOM nodes at once likely needs virtualization, not memoization ✓
- C. useMemo on the map result fixes it since map allocates a new array each render
- D. memo is useless in React 18 because the compiler auto-memoizes
Correct answer: B. The red flag is optimizing before measuring; a 5,000-node list is a DOM/layout cost that memoization can't fix, and the Profiler would point to virtualization instead.
This effect logs a stale count. Why, and what is the minimal correct fix?
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
const id = setInterval(() => console.log(count), 1000);
return () => clearInterval(id);
}, []);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
- A. The interval closure captured count=0 from the first render; use a ref (or functional read) so the interval reads the latest value ✓
- B. setInterval is unreliable in React; switch to setTimeout recursion
- C. Add count to the dependency array is the only acceptable fix and has no downside
- D. State updates are async so count is always one behind; add a useLayoutEffect
Correct answer: A. The empty-dep effect runs once and its closure permanently captures count=0; reading through a ref (updated each render) or adding count to deps both fix it, but only the ref avoids tearing down the interval every tick.
A CORS request from https://app.example.com sends cookies via fetch(url, { credentials: 'include' }). The server responds with Access-Control-Allow-Origin: * and Access-Control-Allow-Credentials: true. What happens?
- A. It works; * matches every origin including the credentialed one
- B. The browser blocks it: with credentials, the ACAO header must echo the specific origin, not the wildcard * ✓
- C. It works only if SameSite=None is also set on the cookie
- D. The preflight succeeds but the cookie is silently stripped from the actual request
Correct answer: B. The Fetch spec forbids the wildcard when credentials are included; the server must reflect the exact origin (and the browser rejects the response otherwise).
Predict the output:
const obj = {
val: 42,
regular() { return (function () { return this?.val; })(); },
arrow() { return (() => this.val)(); }
};
console.log(obj.regular(), obj.arrow());
- A. 42 42
- B. undefined 42 ✓
- C. 42 undefined
- D. undefined undefined
Correct answer: B. The inner regular function is called plain so its `this` is undefined (strict) giving undefined via optional chaining, while the arrow captures the method's `this` (obj) yielding 42.
Why did React's Fiber architecture replace the old stack reconciler? Pick the most fundamental reason.
- A. Fiber uses less memory by reusing a single tree
- B. Reconciliation was synchronous and uninterruptible; Fiber makes work a linked list of units that can be paused, prioritized, and resumed so high-priority updates aren't blocked ✓
- C. Fiber removed the virtual DOM entirely in favor of direct DOM diffing
- D. Fiber enables server components by moving rendering to the server
Correct answer: B. The stack reconciler recursed synchronously and couldn't be interrupted; Fiber restructures work into resumable units enabling priority scheduling and time-slicing.
A form input feels janky while filtering a huge list on each keystroke. You want the input to stay responsive and the list to update at lower priority without debouncing. Which is the idiomatic React 18 tool, and what's the caveat?
- A. useMemo on the filtered list — it will skip recomputation
- B. useDeferredValue on the filter text — the list renders with a lagging value, but the underlying filtering work must still be cheap enough or you also need virtualization ✓
- C. useCallback on the onChange handler to prevent re-renders
- D. useLayoutEffect to batch the updates synchronously
Correct answer: B. useDeferredValue lets the input update urgently while the list re-renders from a deferred value at lower priority, but it only reprioritizes—it doesn't make an expensive render cheap.
Storing a JWT in localStorage vs an httpOnly SameSite=Strict cookie: which statement is the accurate trade-off?
- A. localStorage is safe because JS on your own origin is trusted
- B. httpOnly cookies are immune to CSRF so no other defense is needed
- C. localStorage is readable by any XSS-injected script (token exfiltration), while an httpOnly cookie is not JS-readable but reintroduces CSRF risk that SameSite/anti-CSRF tokens must address ✓
- D. Both are equivalent since HTTPS encrypts the token in transit
Correct answer: C. localStorage tokens are exposed to XSS; httpOnly cookies block that read but are auto-sent by the browser, so CSRF protections become necessary.
Passing a value through React Context, this consumer re-renders on every provider render even when `user` is unchanged. What's the root cause?
<AuthContext.Provider value={{ user, login, logout }}>
- A. Context always re-renders all consumers regardless of value
- B. The value object literal is a new reference each render, so all consumers re-render; memoize it with useMemo ✓
- C. useContext doesn't support object values
- D. You must wrap consumers in React.memo — context bypasses memo, so it can't be fixed
Correct answer: B. Context compares the value by reference; a fresh object literal each render invalidates all consumers, so the provider value should be memoized (splitting stable vs volatile values also helps).
Two rapid searches: request A (for 're') is slow, request B (for 'react') is fast and arrives first. Without care the UI shows A's results last. Which is the robust fix for this out-of-order async race?
- A. Add a loading spinner so the user waits
- B. Debounce the input to 300ms — this guarantees ordering
- C. Track the latest request (e.g. an AbortController to cancel A, or an ignore flag / request id) so stale responses are discarded ✓
- D. Wrap both in Promise.all so they resolve together
Correct answer: C. Cancelling superseded requests or tagging responses with a request id and dropping any that aren't the latest prevents a slow earlier response from clobbering fresh data; debouncing reduces but doesn't eliminate the race.