How to Handle onChange in React
What you’ll build or solve
You’ll capture user input changes in React and keep the UI synced with state.
When this approach works best
onChange works best when you need to:
Learn React on Mimo
- Keep a text input synced with state, like a search box or form field.
- React to user edits right away, like live validation or live preview.
- Store a selection as it changes, like a plan choice or a toggle.
Skip onChange when you only need the final value on submit, and you do not care about live updates. An uncontrolled input, read on submit, can be simpler in those cases.
Prerequisites
- A React app set up
- Basic JSX knowledge
- Familiarity with
useState
Step-by-step instructions
1) Handle input changes with onChange
React calls onChange when the user changes the input. Pair a value from state with an onChange handler that updates that state.
import {useState }from"react";
exportdefaultfunctionNameField() {
const [value,setValue]=useState("");
return (
<input
value={value}
onChange={(e) =>setValue(e.target.value)}
placeholder="Type your name"
/>
);
}
What to look for:
valueandonChangeshould point to the same state, or the input will feel “stuck.”- The event tells you what changed. Most inputs use
e.target.value. Checkboxes and radios usee.target.checked. onChangeruns on every keystroke for text inputs, so keep the handler quick.
Examples you can copy
Example 1: Search input that filters a list
import {useMemo,useState }from"react";
exportdefaultfunctionSearchList() {
const [query,setQuery]=useState("");
constitems= ["React","Vue","Svelte","Solid"];
constfiltered=useMemo(() => {
constq=query.trim().toLowerCase();
if (!q)returnitems;
returnitems.filter((x) =>
x.toLowerCase().includes(q)
);
}, [query,items]);
return (
<div>
<input
value={query}
onChange={(e) =>setQuery(e.target.value)}
placeholder="Search"
/>
<ul>
{filtered.map((x) => (
<likey={x}>{x}</li>
))}
</ul>
</div>
);
}
This keeps the input controlled and derives filtered results from state.
Example 2: Checkbox that toggles a setting
JavaScript
import {useState }from"react";
exportdefaultfunctionEmailOptIn() {
const [optIn,setOptIn]=useState(false);
return (
<label>
<input
type="checkbox"
checked={optIn}
onChange={(e) =>setOptIn(e.target.checked)}
/>
Email me updates
</label>
);
}
For checkboxes, use checked and e.target.checked, not value.
Example 3: Multi-field form with one handler
import {useState }from"react";
exportdefaultfunctionSignupForm() {
const [form,setForm]=useState({
email:"",
password:"",
});
functionhandleChange(e) {
const { name, value }=e.target;
setForm((prev) => ({
...prev,
[name]:value,
}));
}
return (
<form>
<input
name="email"
value={form.email}
onChange={handleChange}
placeholder="Email"
/>
<input
name="password"
type="password"
value={form.password}
onChange={handleChange}
placeholder="Password"
/>
<buttontype="submit">
Create account
</button>
</form>
);
}
The name attribute decides which field to update. The spread keeps other fields unchanged.
Common mistakes and how to fix them
Mistake 1: Using value for a checkbox instead of checked
What you might do:
<input
type="checkbox"
value={optIn}
onChange={(e) =>setOptIn(e.target.value)}
/>
Why it breaks:
e.target.value is a string, often "on", not a boolean.
Fix: Use checked and e.target.checked.
<input
type="checkbox"
checked={optIn}
onChange={(e) =>setOptIn(e.target.checked)}
/>
Mistake 2: Setting value without onChange
What you might do:
<inputvalue={name}/>
Why it breaks:
The input becomes read-only, so typing does nothing.
Fix: Update state inside onChange.
<input
value={name}
onChange={(e) =>setName(e.target.value)}
/>
Troubleshooting
- If you see “A component is changing an uncontrolled input to be controlled,” initialize state to a real value like
""for text inputs orfalsefor checkboxes. - If typing feels laggy, check for expensive work inside the handler. Move heavy logic outside the handler, or debounce the state used for filtering.
- If the wrong field updates in a form, confirm the input
namematches your state keys. - If the input clears on every keystroke, check that you are not resetting state on each render.
Quick recap
- Use
onChangeto update state when the user changes an input. - Pair
value(orchecked) withonChangeso the input stays in sync. - Read the new value from the event:
valuefor most inputs,checkedfor checkboxes. - For multiple fields, use
nameto update the right key. - Initialize state to avoid controlled/uncontrolled warnings.
Join 35M+ people learning for free on Mimo
4.8 out of 5 across 1M+ reviews
Check us out on Apple AppStore, Google Play Store, and Trustpilot