function Child({ onSelect }) {
return (
<button onClick={() => onSelect("React")}>
Select React
</button>
);
}
function Parent() {
function handleSelect(value) {
console.log(value);
}
return <Child onSelect={handleSelect} />;
}The parent defines handleSelect and passes it down as the onSelect prop. The child doesn't know or care what the function does โ it just calls it, passing back whatever data is relevant (here, the string "React").
function SearchBox({ onSearch }) {
const [query, setQuery] = useState("");
function handleSubmit(e) {
e.preventDefault();
onSearch(query);
}
return (
<form onSubmit={handleSubmit}>
<input value={query} onChange={(e) => setQuery(e.target.value)} />
</form>
);
}
function App() {
const [results, setResults] = useState([]);
function handleSearch(query) {
setResults([`Result for ${query}`]);
}
return <SearchBox onSearch={handleSearch} />;
}Note that the query input's own text is local state owned by SearchBox itself โ only the final submitted value gets communicated up to the parent, a very common and clean division of responsibility.
function Modal({ isOpen, onClose, children }) {
if (!isOpen) return null;
return (
<div className="modal-overlay">
<div className="modal-content">
{children}
<button onClick={onClose}>Close</button>
</div>
</div>
);
}A reusable Modal doesn't know anything about why it should close โ it just calls whatever onClose function its parent gave it, letting the parent fully control whether the modal is open via its own state.
Naming a callback prop something vague like onClick when it actually represents a higher-level action (like submitting a search or selecting an item) makes components harder to understand at a glance. The React convention is to name callback props starting with on followed by a clear description of the event: onSearch, onSelect, onDelete.
Build a parent component that shows a count, and a child Counter component with + and - buttons that call callback props to update the parent's state.
function Counter({ onIncrement, onDecrement }) {
return (
<div>
<button onClick={onDecrement}>-</button>
<button onClick={onIncrement}>+</button>
</div>
);
}
function App() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<Counter
onIncrement={() => setCount(c => c + 1)}
onDecrement={() => setCount(c => c - 1)}
/>
</div>
);
}
Q Is 'callback prop' a special React feature?
No โ it's just a regular JavaScript function passed as a prop, following a naming convention (onSomething). React doesn't do anything special with it beyond passing it down like any other prop value.
Q Can a child component call a callback prop with multiple arguments?
Yes โ a callback prop is just a normal function, so it can be called with as many arguments as the parent's function definition expects, e.g. onUpdate(id, newValue).