Rendering and data flow
Follow one-way data flow
Trace state from its owner down through props and trace interactions back up through callback props.
Unidirectional data flow means data has one, and only one, way to move through the application. In React, that direction is down: state is passed from its owner to child components through props, and nothing flows back up on its own.
What travels upward instead are events. A child receives a callback prop and calls it to report what happened:
function TaskPage() {
const [tasks, setTasks] = useState(initialTasks)
function handleToggle(id) {
setTasks(tasks => tasks.map(task =>
task.id === id
? { ...task, done: !task.done }
: task
))
}
return <TaskList tasks={tasks} onToggle={handleToggle} />
}
Inside TaskList, a child renders each task and reports clicks through the callback prop:
<button onClick={() => onToggle(task.id)}>
{task.title}
</button>
Follow one interaction through this component:
TaskPageowns the task state.- It passes task snapshots down as props.
- A child reports intent with
onToggle(id). - The owner updates state.
- React renders new props down the tree.
The child does not mutate the task it received or search the DOM for another component. It only reports what happened. The owner remains the one source of truth.
Why organize an application this way? Because it limits where data can come from. When every value has exactly one owner and one downward path, you have more control over your data, and debugging becomes tracing: you know what is coming from where. Two-way bindings, where a child edits shared data directly, remove that guarantee.
The rule has a structural consequence worth memorizing. Changing state on a component affects only that component and its children. It never affects the parent, the siblings, or anything else in the tree. This is why state often gets moved up: when two components need the same value, the state must live in a common ancestor so it can flow down to both.
This model also gives you a debugging procedure. When a value is surprising, find the component that owns it. Follow the prop downward to where it renders and the callback upward to where it changes. React DevTools shows both points, so the search is short.
Draw the owner, prop, child, callback, and next render for one interaction before changing code.
Lesson completed