Thinking in React
You now have every tool: components, props, state, lists, conditionals, controlled inputs, lifted state, derived values. The remaining skill is the design process. The React team's classic recipe has five steps. Our example: a filterable product table with a search box and an 'in stock only' checkbox.
Step 1: break the UI into a component hierarchy. Draw boxes around every distinct piece:
FilterableProductTable ├── SearchBar (text input + checkbox) └── ProductTable (the rows) └── ProductRow (one product)
Step 2: build a static version. No state, all props, hard-coded data flowing down. It renders once and proves the structure. Static versions are mostly typing, interactivity is mostly thinking, keep them separate.
Step 3: find the minimal state. List every piece of data, keep only what fails ALL of these tests: passed in as props, never changes, or computable from other state/props (lesson 8-2).
- product list → passed in as a prop, not state
- search text → changes, not computable: state
- checkbox value → changes, not computable: state
- filtered rows → computable from products + search text + checkbox: derived
Two pieces of state for the whole feature.
Step 4: decide where state lives. Who reads the search text? SearchBar (to display it) and ProductTable (to filter). Their closest common parent is FilterableProductTable, so state lives there (lesson 8-1).
Step 5: add inverse data flow. SearchBar gets onSearchChange and onStockChange function props so typing updates the parent's state, the controlled-input loop from lesson 6-1 stretched across components.
Why the filtered rows are not state
Applying step 3 to the product table, the filtered rows are computable during render from products, the search text, and the checkbox, so storing them would duplicate truth.
The computation is one line, filtered = products.filter(...), using the current query and checkbox value. Anything computable from existing state and props is derived and computed fresh each render.
Storing them would create a third thing to keep in step with two others. Every keystroke and every checkbox click would have to remember to recompute and store the list, and one forgotten path leaves the table showing results for a filter that is no longer selected.
Minimal state means every remaining piece is an independent fact, which is a useful test to apply out loud. The search text cannot be worked out from anything else on the page, and the filtered rows can, and that difference is the whole decision.
Note that this is also the answer to a very common shape of bug report, where a list updates one keystroke behind. That symptom nearly always means the visible rows are stored rather than derived, and computing them removes the bug rather than fixing it.
Placing theme state for distant consumers
For a ThemeToggle in Settings and a ThemedHeader at the top of the page, the theme goes in their closest common ancestor, even if that is App at the very top.
The rule does not care how far apart the consumers are. State climbs to the closest common parent of everyone who needs it, and when the consumers are in different regions of the page, that parent is often App.
Distance does have a cost, and it is ergonomic rather than architectural. The value has to travel through every intermediate component as props, and components that neither read nor change the theme end up declaring it just to pass it along, which is called prop drilling.
React's context feature exists to skip those middle layers, letting a provider near the top publish a value that any descendant can read directly. It is a delivery mechanism rather than a different ownership model, so the answer to where state lives is unchanged, and it is a topic for after this course.
Note that a theme is the textbook case for context precisely because it is read everywhere and changed in one place. State that only two nearby siblings share is better off lifted the normal way, since context adds indirection that pays off only at scale.
What the static version proves
Steps 1 and 2 build a props-only version first because it proves the component structure, meaning the hierarchy is right and props carry the data down to where it renders.
It cannot prove behavior, since it has no state and nothing responds to a click. What it shows is data flowing down through the right boxes, which is the half of the design that is hardest to change later.
With the skeleton verified, adding state becomes a small isolated step: find the minimal state, place it, and wire the events up. That is three narrow decisions instead of designing structure and behavior simultaneously and debugging both at once.
The practical difference is where mistakes surface. A wrong hierarchy discovered during the static pass costs a few minutes of moving JSX, and the same mistake discovered after state and handlers exist means moving state, rewriting props, and rethreading callbacks.
Static versions are mostly typing while interactivity is mostly thinking, which is the real argument for keeping them separate. Mixing them means doing the thinking while distracted by the typing.