What is unidirectional data flow in React?
Unidirectional data flow means data in React moves one way only — from parent components down to children via props. Children cannot directly modify their parent's data; they communicate back by calling callbacks the parent passed in.
Predictable — you can trace where any piece of data came from by following the tree upward.
Easier debugging — only one place can change a piece of state; bugs are easier to localize.
Source of truth — state lives at one level; lower components are pure functions of props.
Callbacks bubble up — child events trigger parent-supplied functions; the parent decides what to update.
Lift state up — if siblings need shared data, hoist it to the closest common ancestor.
Contrast with two-way binding — AngularJS-style two-way binding lets children mutate parent data directly; harder to reason about at scale.
function Parent() {
const [items, setItems] = useState(['Apple', 'Banana']);
const addItem = (item) => {
setItems([...items, item]);
};
return (
<div>
<ItemList items={items} /> {/* Data flows down */}
<AddItemForm onAdd={addItem} /> {/* Callback flows down */}
</div>
);
}
function ItemList({ items }) {
return (
<ul>
{items.map((item, i) => <li key={i}>{item}</li>)}
</ul>
);
}
function AddItemForm({ onAdd }) {
const [value, setValue] = useState('');
return (
<form onSubmit={(e) => { e.preventDefault(); onAdd(value); setValue(''); }}>
<input value={value} onChange={(e) => setValue(e.target.value)} />
<button type="submit">Add</button>
</form>
);
}Parent owns the items state and passes it down to ItemList (data flows down as props). AddItemForm receives a callback (onAdd) and calls it when the user submits.
The parent updates its state, which triggers a re-render, and the new items flow down again. Data always moves in one direction: parent -> child.
Explain the flow: state -> props -> render -> callback -> state update -> re-render. Compare with two-way binding to show you understand the trade-off: predictability vs convenience.