Verified against Claude Code · 2026-07-25
Decide whether this state needs lifting, context, or an external store
A decision-framework prompt that picks the right home for a specific piece of shared state based on update frequency, consumer spread, and persistence needs, instead of defaulting to context for everything.
The prompt
Ready to copy — highlighted parts are example details you can swap.
You are deciding where one specific piece of state should live in a React app — lifted to a common parent, placed in Context, or moved into an external store such as Zustand, Jotai, or Redux Toolkit — based on how it is actually used, not by default habit or whatever the last piece of state used. STATE The current selected rows in a large data table, used for bulk actions. COMPONENT TREE DataTable owns it today; a BulkActionsBar sibling and a SelectionCount badge in a totally separate header component both need to read it. UPDATE FREQUENCY Changes on every row checkbox click — could be dozens of times per session, but never per keystroke or per animation frame. PERSISTENCE REQUIREMENT No — selection should reset the moment the user navigates away from this table. DECISION FRAMEWORK Before applying any rule below, check whether this state actually belongs in the URL rather than in any in-tree home at all — a filter, a selected tab, a search query, or anything else the user would expect to survive a page refresh or be shareable via a link is arguably not component state, Context state, or store state, but a URL search parameter or route segment, and forcing it into one of the three in-tree homes when a link should have captured it is a UX regression dressed up as an architecture decision. If the URL genuinely does not apply, walk through these in order and stop at the first rule that applies, rather than evaluating all of them and picking your favorite. First, if only one component and its direct children need this state, lift it to their nearest common parent — do not reach for Context for a two-level prop pass just because Context exists. Second, if many components across distant branches of the tree need to read the state, but it changes rarely — a theme, the current user, feature flags — Context is appropriate, but split it into its own provider rather than bundling it with other, more frequently-changing state inside the same context value. Third, if the state changes frequently — on every keystroke, every scroll event, every animation frame — and is read by components that should not re-render on every single change, Context is the wrong tool regardless of how rarely it changes elsewhere in the app: every consumer of a context re-renders on every value change, regardless of which slice of that value the particular consumer actually reads. Use an external store with selector-based subscriptions instead. Fourth, if the state needs to persist across route changes, survive a full remount, or be read from outside the React tree entirely — analytics code, a service worker — it belongs in an external store, not component state or Context, regardless of how few components currently read it. OUTPUT FORMAT 1. Which rule applied and why, in one paragraph, including which earlier rules you checked and ruled out first. 2. The recommended approach with a short code sketch, not a full implementation, showing the actual shape of the solution. 3. What would change your answer — the specific condition that would push this recommendation to a different tier if it later turned out to be untrue.
Customize
Optional — swap in your own details for the highlighted parts above.
Why this works
The re-render mechanic cited in the third rule is a real, documented React behavior, not folklore: every component that calls useContext on a given context re-renders whenever that context's Provider value changes, regardless of which slice of the value that particular consumer actually reads — there is no built-in selector mechanism in Context itself — which is exactly why high-frequency state in Context becomes a measurable performance problem while low-frequency state in Context, like a theme or the current user, is genuinely fine and does not need an external store at all. Structuring the answer as an ordered list with an explicit stop condition prevents the most common failure mode for this exact class of question: an LLM listing all three options with generic pros and cons for each and never actually committing to one for the specific case in front of it, which reads as thorough but leaves the real decision right back with the person who asked. Requiring persistence and out-of-React access as their own separate, later-checked rule matters because these needs can exist even when update frequency and consumer spread would otherwise both say Context is fine — a rarely-changing piece of state that nonetheless needs to survive a full page remount is still wrong for Context, since Context state lives inside the React tree and disappears when that tree unmounts. Asking for "what would change your answer" forces the recommendation to name its own falsification condition, turning an architectural opinion into something a reviewer can actually check against reality months later instead of an unfalsifiable preference. Naming the URL as a candidate home before evaluating lift, Context, or a store closes a gap most state-placement frameworks skip entirely: a piece of state that determines what the user sees but is not reflected in the URL cannot be shared via a link, cannot survive a refresh, and breaks the browser's own back-button expectation, and no amount of getting the Context-versus-store decision right fixes any of that, because the underlying problem was never really where the state lives in React's tree — it is that the state was modeled as React state at all instead of as navigation state the router already manages.
What you get back
Rule 2 applies: SelectionCount and BulkActionsBar sit in distant branches, and the state changes only on checkbox clicks (dozens of times per session), not on every keystroke or animation frame, so rule 3's re-render concern doesn't bite here. Persistence isn't required either, so rule 4 doesn't apply. A scoped SelectionContext — not an app-wide context — provided just above DataTable, BulkActionsBar, and SelectionCount is the right fit. const SelectionContext = createContext<{ selected: Set<string>; toggle: (id: string) => void } | null>(null); // Provider wraps only the DataTable + BulkActionsBar + SelectionCount subtree, not the whole app. What would change this: if the table grows to thousands of rows with per-row visual state tied to selection — every row re-rendering on any selection change becomes visibly janky — move to a Zustand store with a per-row selector instead, since that's rule 3's condition arriving late.
Verified against
Claude Code Sonnet 4.6 · 2026-07-25
ChatGPT GPT-5.1 · 2026-07-29
Changelog
- 2026-07-25 — Initial publish, verified against Claude Code (Sonnet 4.6) and ChatGPT (GPT-5.1).
Need this built into your business?
If a prompt isn't enough — custom software, built and maintained for you — that's Scult's day job.
EXPLORE CUSTOM SOFTWARE
