Deck 7 - Performance + Rendering + React Internals Flashcards

Re-render causes, keys, memo/useMemo/useCallback, transitions/deferred UI, Suspense/code-splitting, and effect timing. (80 cards)

1
Q

Deck 7 - Performance + Rendering + React Internals (objective)

A

Goal: identify render/perf footguns and propose fixes that improve responsiveness without cargo-cult memoization.
You practice: reconciliation, keys, memo/useMemo/useCallback, transitions, Suspense/code-splitting, and effect timing.
Output style: 1 verdict sentence + 2-3 issues + best fix approach.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Render vs commit (mental model).

A
  • Render: compute what UI should look like.
  • Commit: apply changes to DOM.
  • Perf goal: minimize unnecessary renders and expensive work during render.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Reconciliation and keys (why keys matter).

A
  • React matches list items by key.
  • Stable keys preserve state and reduce DOM churn.
  • Wrong keys cause bugs and extra work.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Batching (what it means).

A
  • React batches state updates in event handlers.
  • Fewer commits; less layout thrash.
  • Async batching differs by environment; do not rely on timing hacks.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

What triggers rerenders?

A
  • State updates, parent rerenders, context value changes, and prop identity changes.
  • Memoization only helps when work is expensive and props are stable.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

React.memo (when it helps).

A
  • Helps when child renders are expensive AND props are referentially stable.
  • Useless if parent passes new objects/functions every render.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

useMemo (when it helps).

A
  • Memoize expensive computations, not cheap ones.
  • Correct deps are mandatory.
  • Use to stabilize derived values passed as props.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

useCallback (when it helps).

A
  • Stabilize callback identity for memoized children.
  • Avoid stale closures by including deps.
  • Do not use everywhere; adds complexity.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Referential equality (core idea).

A
  • Objects/arrays/functions are new each render unless memoized.
  • Identity changes can trigger rerenders in memoized trees.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Avoid expensive work in render.

A
  • Move expensive work out of render, memoize it, or precompute.
  • Avoid sorting/filtering huge arrays on every render.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

List performance (virtualization).

A
  • For large lists, render only visible rows (react-window, etc.).
  • Avoid heavy components per row.
  • Keep row props minimal and stable.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

Transitions (useTransition/startTransition).

A
  • Mark non-urgent updates (e.g., filtering) as transitions.
  • Keeps input responsive under load.
  • Provide pending UI when needed.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

useDeferredValue (when).

A
  • Defer expensive derived UI based on fast-changing input.
  • Useful for search-as-you-type.
  • Works well with transitions.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

Suspense + code splitting (baseline).

A
  • Use React.lazy + Suspense for route-level splitting.
  • Keep boundaries close to async work.
  • Avoid one giant boundary for entire app.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

Effect timing (useEffect vs useLayoutEffect).

A
  • useEffect runs after paint.
  • useLayoutEffect runs before paint and can block rendering.
  • Prefer useEffect unless you must measure layout synchronously.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

Infinite loops (common causes).

A
  • setState during render, effects without correct deps, unstable deps.
  • Fix by moving state updates to events or correcting deps/guards.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q

Context performance (gotcha).

A
  • Context changes rerender all consumers.
  • Split contexts or memoize values.
  • Avoid passing new objects as context value each render.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
Q

SSR/hydration mismatch (baseline).

A
  • Non-deterministic render output causes mismatch.
  • Use useId for IDs; avoid Date.now/Math.random in render.
  • Gate client-only code behind effects.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
19
Q

Measuring performance (tools).

A
  • React DevTools Profiler for rerenders.
  • Browser Performance tab for long tasks.
  • Track Web Vitals (LCP/INP/CLS) where relevant.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
20
Q

Evaluator wording for perf issues.

A

Name the root cause (unnecessary rerenders/expensive render work/unstable identity), impact (jank/slow typing), fix (memoize correctly, split work, transition, virtualize).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
21
Q

Gotcha: using array index as key in a reorderable list.

items.map((item, i) => <Row key={i} item={item} />)
A

Verdict: FAIL
- Issue: index keys break identity on reorder.
- Impact: wrong state/DOM reuse + extra churn.
- Fix: use stable unique key (item.id).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
22
Q

Gotcha: key missing entirely.

items.map(item => <Row item={item} />)
A

Verdict: FAIL
- Issue: missing key.
- Fix: add key={item.id}.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
23
Q

Gotcha: sorting in render every time.

const sorted = items.slice().sort((a,b) => a.name.localeCompare(b.name));
return sorted.map(...);
A

Verdict: PARTIAL FAIL
- Issue: expensive work on every render.
- Fix: useMemo with correct deps or pre-sort upstream.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
24
Q

Gotcha: filtering huge list on every keystroke.

const filtered = items.filter(x => x.name.includes(q));
A

Verdict: PARTIAL FAIL
- Issue: expensive synchronous work blocks typing.
- Fix: useDeferredValue/useTransition and/or debounce + memoization.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
25
Gotcha: React.memo but props change identity every render. ``` const Child = React.memo(({ opts }) =>
); // parent ```
Verdict: FAIL - Issue: new opts object defeats memo. - Fix: memoize opts (useMemo) or pass primitives.
26
Gotcha: useCallback with missing deps (stale closure). ``` const onSave = useCallback(() => api.save(id), []); ```
Verdict: FAIL - Issue: id not in deps; stale id. - Fix: include [id] or compute at call site.
27
Gotcha: useMemo with wrong deps. ``` const v = useMemo(() => compute(a, b), [a]); ```
Verdict: FAIL - Issue: missing b in deps. - Fix: include all deps (or refactor).
28
Gotcha: useMemo used for cheap value. ``` const x = useMemo(() => n + 1, [n]); ```
Verdict: PASS - Note: unnecessary; remove to reduce complexity unless proven hot.
29
Gotcha: setState during render. ``` if (x) setCount(c => c + 1); return
; ```
Verdict: FAIL - Issue: render side effect causes loops. - Fix: move to event/effect with guard.
30
Gotcha: effect updates state without deps. ``` useEffect(() => { setN(n + 1); }); ```
Verdict: FAIL - Issue: runs every render; infinite loop. - Fix: add deps or use functional update with guard.
31
Gotcha: unstable function in deps causes effect rerun. ``` useEffect(() => { doThing(); }, [() => doThing()]); ```
Verdict: FAIL - Issue: new function each render. - Fix: put doThing in deps (memoize if needed) or inline body.
32
Gotcha: context value recreated each render. ``` {children} ```
Verdict: PARTIAL FAIL - Issue: new object triggers rerenders for all consumers. - Fix: memoize value with useMemo, or split contexts.
33
Gotcha: useLayoutEffect used for async fetch. ``` useLayoutEffect(() => { fetchData(); }, []); ```
Verdict: FAIL - Issue: layout effect blocks paint. - Fix: useEffect for async work.
34
Gotcha: measuring layout on every render. ``` useLayoutEffect(() => { el.getBoundingClientRect(); }); ```
Verdict: PARTIAL FAIL - Issue: forces layout each commit. - Fix: throttle/measure only when needed; use ResizeObserver.
35
Gotcha: unnecessary rerenders due to inline handler. ``` doThing(id)} /> ```
Verdict: PARTIAL - Issue: new function each render can defeat memo. - Fix: useCallback if Child is memoized and re-renders are costly.
36
Gotcha: memoizing everything with useCallback.
Verdict: PARTIAL FAIL - Issue: cargo-cult memo increases complexity and can hurt perf. - Fix: memoize only hot paths; measure first.
37
Gotcha: derived state duplicated. ``` const [fullName, setFullName] = useState(first + ' ' + last); ```
Verdict: PARTIAL FAIL - Issue: derived state can drift. - Fix: derive in render or useMemo; store source state only.
38
Gotcha: JSON.stringify in deps. ``` useEffect(() => { ... }, [JSON.stringify(filters)]); ```
Verdict: PARTIAL FAIL - Issue: expensive and brittle. - Fix: stabilize filters object or use primitives in deps.
39
Gotcha: large list without virtualization.
Verdict: PARTIAL - Issue: too many DOM nodes. - Fix: virtualize list and keep rows light.
40
Gotcha: suspense boundary too high. ``` }> ```
Verdict: PARTIAL - Issue: whole app blanks during small fetches. - Fix: add smaller boundaries near async regions/routes.
41
Gotcha: lazy import inside render. ``` function App() { const Page = React.lazy(() => import('./Page')); return ; } ```
Verdict: PARTIAL FAIL - Issue: redefines lazy component each render. - Fix: define lazy import at module scope.
42
Gotcha: non-deterministic render (hydration mismatch). ```
{Date.now()}
```
Verdict: FAIL - Issue: server/client mismatch. - Fix: compute in effect or pass from server.
43
Gotcha: Math.random in keys. ``` items.map(x => ) ```
Verdict: FAIL - Issue: keys change every render; full remount. - Fix: stable keys (id).
44
Gotcha: unstable id generation per render. ``` const id = 'x-' + Math.random(); return ; ```
Verdict: FAIL - Issue: id changes each render; label breaks. - Fix: useId() or stable id.
45
Gotcha: transition not used for heavy filtering.
Verdict: PARTIAL - Issue: expensive derived UI can block typing. - Fix: startTransition or defer derived value.
46
Gotcha: startTransition used for urgent update (wrong).
Verdict: PARTIAL - Issue: urgent UI might lag. - Fix: keep urgent updates outside transition; transition the expensive derived work.
47
Gotcha: effect depends on unstable object. ``` useEffect(() => { fetchStuff(filters); }, [filters]); ```
Verdict: PARTIAL - Issue: filters identity changes; refetch churn. - Fix: stabilize filters with useMemo or use primitives in deps.
48
Gotcha: missing cleanup for event listener. ``` useEffect(() => { window.addEventListener('scroll', onScroll); }, []); ```
Verdict: FAIL - Issue: no cleanup. - Fix: return cleanup to remove listener.
49
Gotcha: cleanup uses different function reference. ``` useEffect(() => { window.addEventListener('scroll', () => onScroll()); return () => window.removeEventListener('scroll', () => onScroll()); }, [onScroll]); ```
Verdict: FAIL - Issue: removeEventListener uses different function. - Fix: use stable handler reference.
50
Gotcha: re-render storm from multiple setState calls.
Verdict: PARTIAL - Issue: extra renders. - Fix: batch updates or compute once and set once.
51
Gotcha: index key nuance.
Verdict: PASS - Note: index key is acceptable only for static lists that never reorder/insert/delete.
52
Gotcha: heavy component on every route, no code-splitting.
Verdict: PARTIAL - Issue: large bundle and slow startup. - Fix: route-level lazy loading/code splitting.
53
Gotcha: inline style object passed to memo child. ``` ```
Verdict: PARTIAL - Issue: new object each render. - Fix: memoize style or use className; only if Child is memoized/hot.
54
Gotcha: using React.memo without profiling.
Verdict: PARTIAL - Issue: premature optimization. - Fix: profile first; apply memo where it reduces costly rerenders.
55
Gotcha: expensive selector not memoized.
Verdict: PARTIAL - Issue: recompute each render. - Fix: memoize selectors; keep inputs stable.
56
Gotcha: passing whole object to memoized child with frequent identity changes.
Verdict: PARTIAL - Fix: pass only primitives or memoize derived props.
57
Gotcha: useEffect to mirror props into state. ``` useEffect(() => setValue(prop), [prop]); ```
Verdict: PARTIAL - Issue: extra render; derived state. - Fix: derive directly unless editing locally.
58
Gotcha: reading then writing layout in a tight loop.
Verdict: PARTIAL FAIL - Issue: layout thrash. - Fix: batch reads then writes; avoid per-item measurements.
59
Gotcha: effect loop due to unstable deps array creation.
Verdict: PARTIAL - Issue: deps change each render. - Fix: stabilize deps inputs or move constants outside.
60
Gotcha: rendering 10k rows with complex row components.
Verdict: PARTIAL - Fix: virtualize and simplify row; memoize row if needed.
61
Scenario: verdict + 3 issues. ``` const Row = React.memo(function Row({ item, onSelect }) { return ; }); function List({ items }) { return items.map((item, i) => ( console.log(id)} /> )); } ```
Verdict: FAIL 1) index key breaks identity on reorder 2) onSelect recreated each render defeats memo 3) likely unnecessary inline handler churn; pass stable handler and id
62
Scenario: best fix for memoized child receiving object prop.
Memoize the object with useMemo or pass only needed primitives; ensure deps are correct.
63
Scenario: when does useCallback help?
When passing callbacks to memoized children where callback identity would otherwise trigger rerenders; not for every handler.
64
Scenario: correct use of useDeferredValue.
Use deferredQuery = useDeferredValue(query) and filter large lists using deferredQuery to keep typing responsive.
65
Scenario: keys rule of thumb.
Keys must be stable and unique across siblings; prefer ids; avoid Math.random and index for dynamic lists.
66
Scenario: hydration mismatch examples.
Non-deterministic output (Date.now/Math.random), environment branching, or mismatched ids. Fix via useId/effects/server props.
67
Scenario: when to use useLayoutEffect?
When you must measure layout and synchronously re-render before paint (rare). Otherwise useEffect.
68
Scenario: one-liner for expensive render work.
PARTIAL FAIL - The component does expensive work during render on every update, causing jank; memoize/hoist or defer with transition.
69
Scenario: how to confirm rerender cause?
Use React DevTools Profiler; identify which props/context changed and whether identity changes drive rerenders.
70
Scenario: list virtualization trigger.
Use virtualization when DOM size or render cost impacts scroll/INP; render only visible rows.
71
Scenario: correct placement of React.lazy.
Define lazy imports at module scope and wrap with a focused Suspense boundary.
72
Scenario: correct use of startTransition.
Keep urgent updates normal; wrap expensive derived updates (filter/sort) in startTransition.
73
Scenario: context perf fix.
Split context by concern and memoize provider value; avoid new objects each render.
74
Scenario: clean event listener pattern.
Use stable handler reference and cleanup in effect; avoid anonymous functions in add/remove.
75
Scenario: one-liner for bad keys.
FAIL - Unstable keys cause remounts and state bugs; use stable unique identifiers.
76
Checklist: performance review top 5.
1) Stable keys 2) Avoid expensive work in render 3) Memo only hot paths (memo/useMemo/useCallback) 4) Use transitions/deferred value for heavy filtering 5) Virtualize large lists; verify with profiler
77
Checklist: memoization decision.
Is render expensive? Are props stable? Is rerender frequent? Will memo reduce work? Can you verify via profiling?
78
Checklist: identity pitfalls.
Inline objects/arrays/functions Context value objects Deps with unstable values Keys that change Non-deterministic render output
79
Checklist: effect timing.
useEffect for async work/subscriptions Cleanup listeners/requests useLayoutEffect only for sync layout measurement Guard deps to avoid loops
80
Checklist: evaluator wording for perf issues.
Name issue (unnecessary rerender/expensive render), impact (jank/slow typing), fix (stabilize identity, memo correctly, defer work, split/virtualize).