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:

  • 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:

  • value and onChange should 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 use e.target.checked.
  • onChange runs 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 or false for 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 name matches your state keys.
  • If the input clears on every keystroke, check that you are not resetting state on each render.

Quick recap

  • Use onChange to update state when the user changes an input.
  • Pair value (or checked) with onChange so the input stays in sync.
  • Read the new value from the event: value for most inputs, checked for checkboxes.
  • For multiple fields, use name to update the right key.
  • Initialize state to avoid controlled/uncontrolled warnings.