Consider this code:
```js
console.log('A');
setTimeout(() => console.log('B'), 0);
Promise.resolve().then(() => console.log('C')).then(() => console.log('D'));
queueMicrotask(() => console.log('E'));
console.log('F');
```
What is the exact console output order?
- A. A F C E D B ✓
- B. A F B C E D
- C. A F C D E B
- D. A F E C D B
Correct answer: A. Synchronous logs (A, F) run first, then all microtasks in enqueue order (C and E queued before D, which is chained after C), then the setTimeout macrotask (B).
A component list re-renders every item on each parent update despite `React.memo` on the child. The parent passes `onSelect={() => handle(id)}` and `style={{ margin: 4 }}` as props. Why does memo fail, and what is the minimal correct fix?
- A. memo does a deep comparison that is too slow; switch to useMemo on the whole list
- B. The inline arrow and object literal create new references each render, breaking memo's shallow prop check; memoize the callback with useCallback and hoist/memoize the style object ✓
- C. React.memo only works on class components; convert children to PureComponent
- D. memo ignores function props by design; wrap the child in useTransition
Correct answer: B. React.memo does a shallow reference comparison, and new inline function/object literals produce fresh references every render, so stabilizing them with useCallback and a memoized/constant style restores memoization.
You implement a trailing-edge debounce. A user types 5 characters within the wait window, then stops. With a correct trailing-only debounce (wait=300ms), how many times does the wrapped function execute and with which argument?
- A. 5 times, once per keystroke
- B. 1 time, with the argument from the last (5th) call ✓
- C. 1 time, with the argument from the first call
- D. 2 times: once leading, once trailing
Correct answer: B. A trailing debounce resets its timer on every call and only fires once after activity stops, invoking the function with the most recent arguments captured at the last call.
This custom hook has a bug:
```js
function useInterval(callback, delay) {
useEffect(() => {
const id = setInterval(() => callback(), delay);
return () => clearInterval(id);
}, [delay]);
}
```
What happens and why?
- A. It leaks intervals because the cleanup never runs
- B. The interval always invokes the callback captured on the first render with the delay, causing a stale-closure bug because callback is not in the deps and not stored in a ref ✓
- C. It throws because callback is a function and cannot be a dependency
- D. It re-creates the interval on every render, causing excessive timers
Correct answer: B. Because `callback` is omitted from the dependency array, the interval closes over the first render's callback and keeps calling that stale version; the standard fix stores callback in a ref updated each render.
In React 18 concurrent rendering, you wrap a state update that filters a large list in `startTransition`, while the text input's own `setState` stays outside it. What behavior does this specifically produce?
- A. The input update is delayed so both stay in sync
- B. The urgent input update stays responsive and can interrupt/preempt the in-progress non-urgent list render, which React may throw away and restart ✓
- C. Both updates are batched into a single synchronous commit
- D. The list update runs on a Web Worker off the main thread
Correct answer: B. Transitions mark the list update as interruptible/non-urgent, so a higher-priority input update can preempt the in-progress render, keeping typing responsive while React discards and restarts the stale transition render.
Predict the output:
```js
const obj = {
val: 42,
getVal: function () { return (() => this.val)(); },
getValBad: function () { return function () { return this.val; }(); }
};
console.log(obj.getVal());
console.log(obj.getValBad());
```
(non-strict mode)
- A. 42 then 42
- B. 42 then undefined ✓
- C. undefined then undefined
- D. 42 then throws TypeError
Correct answer: B. The arrow function lexically inherits `this` from getVal (obj), returning 42, while the plain IIFE is called as a standalone function so its `this` is the global object, whose `val` is undefined.
For an image-heavy product landing page, LCP is 4.1s. The LCP element is a hero `<img>` loaded via a JS component after hydration. Which single change most directly improves LCP?
- A. Add `loading="lazy"` to the hero image
- B. Server-render the hero `<img>` in the initial HTML with `fetchpriority="high"` and a preload, so it isn't blocked on JS/hydration ✓
- C. Convert the whole page to client-side rendering to reduce TTFB
- D. Wrap the hero component in React.lazy and Suspense
Correct answer: B. LCP is delayed because the largest element is discovered only after JS runs; emitting the image in the initial HTML with high fetch priority/preload lets the browser start the download immediately during the critical rendering path.
Two independently deployed micro-frontends via Webpack Module Federation both list React as a shared singleton but pin different minor versions. At runtime a hook throws "Invalid hook call." What is the root cause?
- A. Module Federation cannot share React at all
- B. With `singleton: true` but incompatible `requiredVersion` ranges, two React copies get loaded, so components and the reconciler use different React instances/dispatchers ✓
- C. React hooks are globally disabled in federated modules
- D. The shell must re-export React from a CDN for singletons to work
Correct answer: B. A hook call needs one React instance; when version ranges don't satisfy the singleton constraint, Webpack loads a second React copy, splitting the internal dispatcher and triggering the invalid-hook-call error.
What does this TypeScript evaluate `T` to?
```ts
type Unwrap<T> = T extends Promise<infer U> ? Unwrap<U> : T;
type T = Unwrap<Promise<Promise<string>>>;
```
- A. Promise<string>
- B. Promise<Promise<string>>
- C. string ✓
- D. unknown
Correct answer: C. The conditional type recursively unwraps nested Promises using `infer`, so both Promise layers are stripped, leaving `string`.
With TanStack Query, you do an optimistic update in `onMutate`, then the mutation fails on the server. To correctly restore prior UI, what must `onMutate`/`onError` do?
- A. Nothing; React Query auto-rolls back all optimistic writes
- B. In onMutate, cancel in-flight queries, snapshot the previous cache value, and write the optimistic value; in onError, restore that snapshot; then invalidate in onSettled ✓
- C. Call queryClient.clear() in onError to wipe stale data
- D. Set staleTime to 0 so the failed value auto-corrects on next render
Correct answer: B. React Query does not auto-rollback manual cache writes; the correct pattern cancels outgoing refetches, snapshots the previous value for restoration on error, and revalidates on settle.