PATTERN Cited by 1 source
Conditional child state scoping¶
Intent¶
Move expensive / rarely-active state into conditionally-rendered child components so the state and its cost exist only when the state is active — not multiplied by every parent instance that could have the state.
Context¶
React idioms commonly push state into the component that might display it — e.g. a diff-line component owning "is there a comment on this line?" and "is the context menu open?" state, even though the vast majority of diff lines never have a comment and never have a menu open. At small scale this is clean. At hot-path scale (concepts/hot-path) — 10,000+ instances — the pattern's cost compounds:
- Every instance pays state-management overhead, even the 99 % that never use it.
- Re-renders cascade: state changes in one instance's rarely- used branch trigger unnecessary reconciliation passes on siblings.
- Memory: per-instance hooks, closures, refs live as long as the parent renders.
This is the state-scope-aligned-with-likelihood failure. The SRP framing applies: the diff-line component's responsibility is rendering code, not managing the commenting UI that 99 % of lines never trigger.
Mechanism¶
- Identify state that is (a) expensive, (b) rarely active in any given instance. Typical candidates in web UIs: comment threads, context menus, hover popovers, inline edit forms.
- Extract that state — and the components using it — into a dedicated child component.
- Conditionally render the child only when the state is active:
- Look up the activation condition via O(1) key-based access
(patterns/constant-time-state-map) — checking a
Mapis cheap enough to run on every line without regressing the common case.
Canonical instance¶
GitHub's Files-changed tab v2 — "The most impactful change from v1 to v2 was moving app state for commenting and context menus into their respective components. Given GitHub's scale, where some pull requests exceed thousands of lines of code, it isn't practical for every line to carry complex commenting state when only a small subset of lines will ever have comments or menus open. By moving the commenting state into the nested components for each diff line, we ensured that the diff- line component's main responsibility is just rendering code — aligning more closely with the Single Responsibility Principle." (Source: sources/2026-04-03-github-the-uphill-climb-of-making-diff-lines-performant)
The activation check is implemented via O(1) Map lookup
(patterns/constant-time-state-map): commentsMap['path'][L].
A line with no comments pays one map lookup per render; a line
with comments pays the map lookup and the commenting component's
real cost.
Anti-patterns¶
- Scoping state into children you still render unconditionally.
The pattern's power comes from not rendering the expensive
child when the state is inactive.
{hasComments(...) && <X/>}not<X active={hasComments(...)}>. - Over-scoping. If state changes frequently enough that the child gets repeatedly mounted/unmounted, the mount/unmount cost exceeds the saved render cost. This pattern is for rarely active state, not frequently toggling state.
- Losing parent-level invariants. State scoped to a child that should survive parent re-renders needs lifted state (or state in an external store). The pattern doesn't apply to state the parent is supposed to coordinate.
- Forgetting to look up activation cheaply. If the activation predicate is itself O(n), the saving is reintroduced at the lookup layer. Pair with patterns/constant-time-state-map.
Related¶
- concepts/react-re-render — what this pattern attacks (state scope determines re-render scope).
- concepts/hot-path — where this pattern pays off.
- patterns/component-tree-simplification — companion v1 → v2 pattern at the component axis.
- patterns/single-top-level-event-handler — companion at the event-handler axis.
- patterns/constant-time-state-map — the lookup partner that makes the activation check cheap.
- systems/github-pull-requests — canonical wiki instance.
- systems/react — framework.