Chapter 29: Sharing State Between Components
Core Idea
"Lifting state up" — moving state from two components that need to stay in sync into their closest common parent, then passing it back down as props — is the standard fix whenever sibling components need to reflect or coordinate the same data.
Key Concepts
- Symptom: two sibling components each hold their own local state for logically-the-same value (e.g. two accordion panels each with their own
isActive) and you need only one of them "active"/expanded/selected at a time, or need them to otherwise agree.
- Fix procedure: (1) remove state from the children entirely, (2) pass hardcoded data down from the common parent temporarily to verify the static wiring, (3) add state to the common parent and pass both the value and an updater callback down as props to each child.
- Result: the parent becomes the single source of truth; children become "controlled" — they render based on props and report interactions back up via callback props, rather than deciding anything themselves.
- Single source of truth per piece of state: every distinct piece of state should have exactly one component that owns it — if you find yourself trying to keep two state variables (in two different components) manually synchronized, that's the sign state needs to be lifted rather than duplicated.
Code Examples
function Accordion() {
const [activeIndex, setActiveIndex] = useState(0);
return (
<>
<Panel isActive={activeIndex === 0} onShow={() => setActiveIndex(0)} />
<Panel isActive={activeIndex === 1} onShow={() => setActiveIndex(1)} />
</>
);
}
- What it demonstrates: state lifted to the parent
Accordion so exactly one Panel can be active — each Panel is now controlled purely by props (isActive) and a callback (onShow).
Key Takeaways
- The moment two components need to agree on a value, that value's
useState belongs in their closest common parent, not in either of them.
- "Controlled component" just means: no local state of its own for that concern, driven entirely by props and reporting changes via callback props.
- This chapter is Ch 3's Step 4 (Identify where state should live) worked through as a concrete before/after refactor.
Connects To
- Ch 3 (Thinking in React): Steps 4-5, the abstract version of this lift-state-up + inverse-data-flow pattern.
- Ch 30 (Preserving and Resetting State): what happens to a lifted-out child's state when it's remounted at a new position.