Deck 16 - React App Architecture / Component API Design Flashcards

Boundaries, state placement, data flow, component APIs, composition patterns, and architecture review gotchas with senior-grade verdict wording. (80 cards)

1
Q

Deck 16 - React App Architecture / Component API Design (objective)

A

Goal: design and review React app architecture like a senior: boundaries, state placement, data flow, component APIs, and maintainable patterns.
You learn: what/why (under the hood), common anti-patterns, and evaluator-grade review wording.
Output style: PASS/PARTIAL/FAIL + 2-3 issues + fix approach.

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

Mental model: separation of concerns (UI vs domain vs data).

A

UI components render and handle interactions.
Domain logic (rules/transforms) should be testable without React.
Data layer handles fetching/caching/serialization at boundaries.

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

Mental model: boundaries reduce blast radius.

A

Well-defined boundaries make changes local.
Examples: API client boundary, feature modules, component boundaries.

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

Mental model: colocate state by ownership.

A

State should live at the lowest common ancestor of the components that need it.
Avoid lifting too high (prop drilling) and too low (duplicated state).

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

Mental model: derived state should be computed, not stored.

A

If you can derive it from props/state, compute it (useMemo when needed).
Storing derived state causes sync bugs and extra effects.

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

Mental model: single source of truth.

A

Avoid duplicate sources for the same truth (server cache + local copy + URL state).
Pick the authority and derive others from it.

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

Mental model: state types - server vs client vs UI.

A

Server state: fetched data, cached (React Query).
Client state: local app state (auth, preferences).
UI state: transient (open modal, input text).

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

Mental model: push side effects to the edges.

A

Keep components mostly pure.
Do IO in hooks/services; keep rendering code deterministic.

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

Mental model: dependencies flow down, events flow up.

A

Data and configuration typically flow down via props/context.
User actions bubble up via callbacks or state updates.

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

Mental model: composition over inheritance.

A

React encourages composing components and hooks.
Avoid class inheritance patterns; prefer composition and render props/children patterns when needed.

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

Mental model: component API should prevent invalid states.

A

Use prop types/unions to make misuse hard.
Example: Button with href vs onClick - enforce correct combinations.

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

Mental model: stable public interfaces matter.

A

Treat shared components as public APIs.
Breaking changes ripple across app; document and version patterns if needed.

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

Mental model: measure complexity as you design.

A

Complexity increases with props count, conditional branches, and cross-cutting concerns.
Split responsibilities rather than growing ‘god components’.

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

Mental model: file/module organization by feature.

A

Feature folders reduce coupling vs type-based folders.
Example: features/orders/* with components, hooks, api, tests together.

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

Mental model: avoid global context for everything.

A

Context is great for truly global concerns.
Overuse causes rerenders, coupling, and hidden dependencies.

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

Mental model: a ‘container/presenter’ split is a tool, not a rule.

A

Containers handle data and state; presenters render.
Use when it reduces complexity; do not force it everywhere.

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

Mental model: state machines for complex flows.

A

For multi-step flows (auth, checkout), model states explicitly.
Prevents impossible UI states and makes logic testable.

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

Mental model: URL as state (when appropriate).

A

Filters/search/sort/pagination often belong in URL for shareability.
Avoid putting everything in URL (sensitive data, huge payloads).

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

Mental model: the cost of prop drilling vs context vs store.

A

Prop drilling is explicit but noisy.
Context reduces plumbing but can hide dependencies.
Stores (Redux) are powerful for complex shared state; avoid for trivial UI state.

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

Mental model: performance is architecture too.

A

Bad boundaries cause unnecessary rerenders.
Design for predictable render graphs and stable props.

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

Pattern: lift state to lowest common ancestor (rule).

A

If two siblings need to coordinate, lift state to their parent.
If only one component needs it, keep it local.

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

Pattern: avoid syncing props into state.

A

Copying props to state creates stale bugs.
Prefer deriving from props or use controlled patterns.

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

Pattern: controlled vs uncontrolled component API.

A

Controlled: value + onChange from parent.
Uncontrolled: internal state with defaultValue.
Provide both only when necessary; document behavior.

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

Pattern: expose events, not internals.

A

Component APIs should communicate via callbacks (onSelect, onSubmit).
Avoid exposing internal refs/state unless needed (imperative handle).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
25
Pattern: useContext for truly global config.
Theme, i18n, auth session, feature flags. Avoid putting frequently changing values in context unless optimized.
26
Pattern: split contexts by update frequency.
Separate read-only config context from rapidly changing state context. Why: reduces rerender fan-out.
27
Pattern: reducer for complex local state.
useReducer helps when transitions are complex or related. Prefer over many related useState calls; model actions and state transitions.
28
Pattern: domain logic outside components.
Put transforms/formatters/validators in utils/domain modules. Why: testable, reusable, avoids rerender hazards.
29
Pattern: dependency injection via props for testability.
Inject services (api client) or functions for unit testing. Avoid hard-coding globals that are hard to mock.
30
Pattern: error boundaries for crash containment.
Wrap risky areas to prevent whole app crash. Provide fallback UI and logging.
31
Pattern: module boundaries (feature slices).
Keep feature-level routing, API calls, and components together. Expose minimal surface area; avoid cross-feature imports.
32
Pattern: avoid circular dependencies.
Circular imports cause runtime undefined and bundler quirks. Fix by extracting shared code into a lower-level module.
33
Pattern: standardize component layering.
Examples: ui/ (pure), components/ (composed), features/ (business), pages/ (route-level). Consistency makes reviews faster.
34
Pattern: composition via children and slots.
Accept children or render props for flexible layouts. Prefer over prop explosion when adding optional UI regions.
35
Pattern: use 'variants' not booleans for styling.
Use variant: 'primary'|'secondary' rather than many booleans. Prevents invalid combinations and keeps API stable.
36
Pattern: keep side effects in hooks.
Move fetch/subscriptions/timers into hooks. Components remain pure and easier to reason about.
37
Pattern: choose state store only when needed.
Redux/Zustand/Context: use for cross-cutting client state. Do not use store for server cache (use React Query) or trivial UI toggles.
38
Pattern: normalize shared data when needed.
For large entities referenced in many places, normalized caches reduce duplication. But avoid premature normalization for small apps.
39
Pattern: prefer explicit data flow over magic.
Avoid hidden coupling via global singletons. Explicit props/context makes dependencies visible to reviewers.
40
Pattern: document contracts with types.
Define public prop types, action types, and API response types. Types are part of the architecture contract.
41
Gotcha: prop drilling 8 levels deep. ``` ```
PARTIAL - Excessive drilling increases coupling. Consider lifting only where needed, extracting a feature component, or using context/store for truly shared state.
42
Gotcha: copying props into state. ``` function Comp({ value }: { value: string }) { const [v, setV] = useState(value); // ... } ```
FAIL - State can go stale when props change. Prefer controlled component (use value directly) or handle prop changes explicitly with derived logic.
43
Gotcha: boolean soup API. ``` type Props = { primary?: boolean; secondary?: boolean; danger?: boolean }; ```
PARTIAL - Invalid combinations possible. Use a variant union and restrict allowed combinations.
44
Gotcha: mixing server and UI state (duplicate source).
FAIL - Duplicating server data into local state causes drift and bugs. Use server cache as source of truth and derive UI views from it.
45
Gotcha: context used for fast-changing values.
PARTIAL - Large rerender fan-out. Split context, memoize provider values, or move hot state closer to consumers.
46
Gotcha: giant component with fetching + rendering + transforms. ``` function Page() { // fetch // parse // map // format // render table + modals + forms } ```
PARTIAL - Hard to test and review. Split into: data hook + domain transforms + presentational components.
47
Gotcha: component API exposes internal state shape.
PARTIAL - Leaky abstraction. Expose intent-based props/events instead of internal implementation details.
48
Gotcha: passing unstable inline objects causing rerenders. ``` ```
PARTIAL - New object each render can bust memoization. Memoize or move constants outside render.
49
Gotcha: using index as key for dynamic list.
FAIL - Can cause state bugs on reordering/inserts. Use stable unique keys from data.
50
Gotcha: imperative DOM manipulation instead of state.
PARTIAL - Bypasses React rendering model and can desync UI. Prefer state-driven UI; use refs only for escape hatches.
51
Gotcha: custom hook doing too much.
PARTIAL - Hooks should have a clear responsibility. Split into smaller hooks and compose them.
52
Gotcha: hidden cross-feature import.
PARTIAL - Importing deep internals of another feature increases coupling. Export a public API from the feature root.
53
Gotcha: no error boundary for risky subtree.
PARTIAL - Unhandled errors can crash entire app. Add error boundary around isolated sections and log/report.
54
Gotcha: context provider value not memoized. ``` ```
PARTIAL - New value object triggers rerenders. Wrap value in useMemo or separate stable actions from changing state.
55
Gotcha: callback prop name mismatch (API clarity).
PARTIAL - Inconsistent naming (onClick vs handleClick) confuses consumers. Prefer 'onX' for events; keep conventions consistent.
56
Gotcha: prop named 'data' with unclear shape.
PARTIAL - Low clarity. Use specific names (users, orders) and strong types to communicate contract.
57
Gotcha: duplicated validation logic in multiple components.
PARTIAL - Move validation to domain/util module or shared schema. Single source reduces drift.
58
Gotcha: storing derived data in state. ``` const [fullName, setFullName] = useState(first + ' ' + last); ```
FAIL - Derived state can drift. Compute fullName from first/last (memoize if expensive).
59
Gotcha: mixing navigation concerns into leaf components.
PARTIAL - Makes component less reusable. Prefer passing href or action callback from parent/router layer.
60
Gotcha: over-using global store for UI toggles.
PARTIAL - Increases complexity and coupling. Keep local UI state local unless multiple distant areas truly need it.
61
Mini-drill: reviewer wording for prop-to-state anti-pattern.
FAIL - Component copies props into local state, which can become stale when props update. Prefer controlled pattern or derive UI directly from props.
62
Mini-drill: reviewer wording for boolean soup.
PARTIAL - Multiple boolean props create invalid combinations and unclear API. Replace with a single variant prop (union) and enforce allowed combos.
63
Mini-drill: reviewer wording for context rerender issue.
PARTIAL - Context value changes on every render, causing broad rerenders. Memoize provider value or split context by update frequency.
64
Mini-drill: reviewer wording for giant component.
PARTIAL - Component mixes data fetching, transforms, and UI rendering. Split into a data hook + pure presentational components for clarity and testability.
65
Mini-drill: verdict on cross-feature deep imports.
PARTIAL - Importing internal modules across features increases coupling. Expose a public API from the feature root and import from there.
66
Checklist: architecture review top 10.
1) Clear boundaries (feature/data/domain) 2) State placement correctness 3) No duplicated sources of truth 4) Derived state computed, not stored 5) Component APIs prevent invalid combos 6) Side effects isolated in hooks 7) Context usage scoped and optimized 8) Stable keys and stable props 9) Error handling boundaries 10) Testability and dependency injection
67
Pattern: presentational + container (example). ``` // Container function UsersPage() { const { data, isLoading } = useUsers(); return ; } // Presentational function UsersTable({ users, loading }: { users: User[]; loading: boolean }) { if (loading) return ; return
    {users.map(u =>
  • {u.name}
  • )}
; } ```
PASS - Fetching/state in container; rendering in presentational component. Improves testability and isolates side effects.
68
Pattern: discriminated props for component variants (example). ``` type ButtonProps = | { kind: 'button'; onClick: () => void; href?: never } | { kind: 'link'; href: string; onClick?: never }; function Action(props: ButtonProps) { return props.kind === 'link' ? Go : ; } ```
PASS - API prevents invalid combinations and documents intent.
69
Pattern: split context by update frequency (example). ``` const AuthStateCtx = createContext(null); const AuthActionsCtx = createContext<{ logout: () => void } | null>(null); ```
PASS - Reduces rerender fan-out by separating changing state from stable actions.
70
Pattern: URL state for filters (high level).
Use URL query params for search/sort/page when shareable and bookmarkable. Keep validation and defaults centralized (parse + serialize functions).
71
Anti-pattern: store server cache in Redux (why).
Server cache needs normalization/invalidation and is solved by React Query/SWR. Redux is better for client state and app events; do not duplicate server cache.
72
Anti-pattern: useEffect for derived state syncing.
Effects to keep state in sync are usually a smell. Prefer deriving values directly in render or using memoization.
73
Anti-pattern: magic context for everything.
Global context hides dependencies. Prefer explicit props or feature-scoped context; reserve app-level context for truly global concerns.
74
Mini-drill: decide where state belongs (rule).
If only one component needs it: local state. If siblings coordinate: lift. If many distant consumers: context/store. If fetched: server cache.
75
Mini-drill: component API design one-liner.
A good component API makes correct usage easy and incorrect usage hard (via types, naming, and defaults).
76
Mini-drill: review wording for duplicated source of truth.
FAIL - Data is duplicated across state sources (server cache + local copy), causing drift. Keep a single authority and derive the UI view from it.
77
Mini-drill: review wording for derived state.
FAIL - Derived value is stored in state and can get out of sync. Compute it from inputs (memoize if expensive) instead.
78
Mini-drill: review wording for unstable props objects.
PARTIAL - Inline objects/functions create unstable props and can trigger rerenders. Memoize or hoist constants where appropriate.
79
Mini-drill: review wording for state machine need.
PARTIAL - Flow has multiple dependent states and edge cases. Model it as a state machine/discriminated union to prevent impossible UI states.
80
Mini-drill: review wording for leaky component API.
PARTIAL - Component exposes internal implementation details via props. Prefer intent-based props/events and keep internals encapsulated.