Choose controlled
Use state when other UI needs the value during editing, or React must transform and validate it immediately.
Event handlers let components respond to people. Input elements can either take their current value from React state or keep that value in the DOM.
An event handler is a function that React runs after an interaction such as a click, key press, form submission, or input change. Handler prop names use camel case, including onClick, onChange, and onSubmit.
function DownloadButton() {
function handleClick() {
alert("Download started");
}
return (
<button onClick={handleClick}>
Download
</button>
);
}
Pass, do not call. onClick={handleClick} waits for a click. onClick={handleClick()} calls the function during rendering and assigns its return value as the handler.
function ProductButton({ productId }) {
function addToCart(id) {
console.log(`Adding ${id}`);
}
return (
<button onClick={() => addToCart(productId)}>
Add to cart
</button>
);
}
React passes an event object to the handler. Its target is the element where the event began, while currentTarget is the element whose handler is currently running.
function SearchForm() {
function handleSubmit(event) {
event.preventDefault();
console.log("Searching");
}
return (
<form onSubmit={handleSubmit}>
<input name="query" />
<button type="submit">Search</button>
</form>
);
}
Most React events bubble. After a child handler runs, the event continues upward and can run handlers on its ancestors. This makes a parent useful for handling interactions from many descendants.
function Toolbar() {
return (
<div onClick={() => console.log("Toolbar clicked")}>
<button onClick={() => console.log("Save clicked")}>
Save
</button>
</div>
);
}
<button
onClick={(event) => {
event.stopPropagation();
console.log("Only the button handles this click");
}}
>
Save
</button>
stopPropagation() controls React propagation.It stops the event from reaching handlers higher in the React tree.
preventDefault() controls browser behavior.It stops a default action such as submitting a form or following a link. It does not stop bubbling.
Use a name such as onClickCapture on an ancestor to observe the event while it travels down toward the target, even if a child later stops bubbling.
A controlled input receives its current value or checked prop from React state. Its change handler updates that state. React state is therefore the source of truth for what appears in the input.
onChange, updates state, and renders the new value.import { useState } from "react";
function NameField() {
const [name, setName] = useState("");
return (
<label>
Name
<input
value={name}
onChange={(event) => setName(event.target.value)}
/>
<span> {name.length} characters</span>
</label>
);
}
Controlled inputs are a good fit when the interface must validate, format, calculate from, synchronize, or reset a value while the person edits it.
A controlled input needs an onChange handler that updates its backing value. Without one, a fixed value makes the input effectively read-only. Initialize text state with "" so the input stays controlled for its whole lifetime.
An uncontrolled input manages its current value itself. React may provide an initial value with defaultValue or defaultChecked, but it does not send a new value on every render. Read the current data when it is needed.
FormData reads named uncontrolled fields when the form is submitted.function ContactForm() {
function handleSubmit(event) {
event.preventDefault();
const data = new FormData(event.currentTarget);
console.log(data.get("email"));
event.currentTarget.reset();
}
return (
<form onSubmit={handleSubmit}>
<label>
Email
<input
name="email"
type="email"
defaultValue="reader@example.com"
/>
</label>
<button type="submit">Send</button>
</form>
);
}
Use state when other UI needs the value during editing, or React must transform and validate it immediately.
Let the DOM keep simple form values when the application only needs them at submission time.
Do not switch one input between controlled and uncontrolled. Choose value with onChange, or choose defaultValue and let the DOM manage later edits. File inputs are always uncontrolled because scripts cannot set their value.
onClick={() => save(id)} different from onClick={save(id)}?
The arrow function waits for the click before calling save. The second expression calls save immediately during rendering and gives React its return value.
preventDefault() stop a click from reaching a parent handler?
No. It stops the browser's default action. Use stopPropagation() when the event should not bubble to React handlers above it.
Use defaultValue. The DOM owns subsequent edits, while a controlled input instead receives its current value from React state.