React onChange Event: Controlled Components Guide
The onChange event is essential for capturing user input in React forms. It fires whenever a user modifies a form element like an input field or dropdown, allowing you to access the new value via event.target.value. By combining onChange with the useState hook, you create "controlled components" where React state becomes the single source of truth for your form data, giving you complete control over validation and data handling.
📖 Introduction
After learning how to handle clicks with onClick, the next most important event in web applications is onChange. This event is the key to creating interactive forms and handling user input in elements like text fields, text areas, and select dropdowns.
This article will cover how to use the onChange event handler to read user input and introduce the fundamental React pattern of a controlled component, where React state is the single source of truth for an input's value.
📚 Prerequisites
Before we begin, please ensure you have a solid grasp of the following concepts:
- React Event Handlers: You should be comfortable with the
onClickhandler and the concept of passing functions as props. - The
useStateHook: A basic understanding of how to declare a state variable and get its setter function is required. - HTML Forms: Familiarity with the
<input>and<form>elements.
🎯 Article Outline: What You'll Master
In this article, you will learn:
- ✅ The
onChangeEvent: How to use theonChangehandler to respond to changes in form inputs. - ✅ Accessing Input Values: How to get the current value of an input from the event object using
event.target.value. - ✅ Controlled Components: The core React pattern for forms, where an input's value is controlled by React state.
- ✅ A Practical Example: Building a simple, interactive form that updates as the user types.
🧠 Section 1: The Core Concept: Handling Input Changes
In HTML, form elements like <input> naturally keep track of their own state. When you type into a text field, the browser's DOM holds the current value.
In React, we often want the component's state to be the "single source of truth" for the input's value. This is called a controlled component. This pattern allows React to control what's in the input field, making it easier to validate input, format data, or react to changes.
The onChange event is the bridge that makes this possible. It fires every time the user changes the value of the input (e.g., on every keystroke in a text field). Inside our onChange handler, we can get the new value and update our component's state, which then causes the component to re-render with the updated value in the input.
💻 Section 2: Building a Controlled Input
Let's build a simple form with a single text input that displays what the user is typing in real-time.
// code-block-1.jsx
import React, { useState } from 'react';
export default function SimpleForm() {
// 1. Declare a state variable to hold the input's value
const [inputValue, setInputValue] = useState('');
// 2. Create an event handler for the onChange event
function handleChange(event) {
// 3. Update the state with the input's new value
setInputValue(event.target.value);
}
return (
<div>
<form>
<label>Your Name:</label>
<input
type="text"
// 4. The input's value is driven by the state variable
value={inputValue}
// 5. The onChange handler updates the state
onChange={handleChange}
/>
</form>
{/* Display the current state value below the form */}
<p>You are typing: {inputValue}</p>
</div>
);
}
Step-by-Step Code Breakdown:
useState(''): We initialize a state variableinputValueto an empty string. This will be the single source of truth for our input field.function handleChange(event): We define our event handler. It receives theSyntheticEventobject as an argument.setInputValue(event.target.value): This is the most important part.event.targetrefers to the DOM node that triggered the event (the<input>).event.target.valuegives us its current value. We then call our state setter function to updateinputValuewith this new value.value={inputValue}: We explicitly set thevalueprop of the<input>to our state variable. This makes it a controlled component. The input will always display whatever is in theinputValuestate.onChange={handleChange}: We wire up our handler to theonChangeevent.
The Data Flow Cycle:
- User types a character.
- The
onChangeevent fires on the<input>. - The
handleChangefunction is called. handleChangecallssetInputValuewith the new value fromevent.target.value.- React triggers a re-render of the component with the new
inputValuestate. - The
<input>'svalueprop receives the new state, and the input displays the updated text.
This cycle happens on every keystroke, ensuring that your React state and the form input are always in sync.
✨ Section 3: Best Practices
- Always Use
valuewithonChange: When creating a controlled component, always provide both thevalueandonChangeprops to the input. Forgetting thevalueprop means the input is no longer controlled by React. Forgetting theonChangehandler means the user won't be able to type in the field (because the value is locked to the state, and there's no way to update the state). - Initialize State: Always initialize the state for your inputs, even if it's just an empty string (
''). This prevents the component from switching between being "uncontrolled" and "controlled," which can cause warnings. - Use for All Form Elements: The
onChangeevent works similarly for<textarea>and<select>elements, making it the universal tool for handling form inputs in React.
Key Takeaways
onChangeFires on Input Change: It's the standard event for handling user input in form elements.event.target.valueHolds the Data: You can access the current value of the input through the event object.- Controlled Components are the Standard: The pattern of linking an input's
valueto state and updating it withonChangeis the idiomatic way to handle forms in React. - The Data Flow is Circular: User input triggers
onChange, which updates state, which causes a re-render, which updates the input's value. - Full Control Over Input: By using controlled components, you can validate input, transform data, or prevent certain characters from being entered.
Frequently Asked Questions
What is the difference between a controlled and an uncontrolled component?
A controlled component's value is managed by React state and updated via onChange. An uncontrolled component manages its own value in the DOM without React state. Controlled components are preferred in React because they give you full control over the data and validation.
Can I use onChange with textarea and select elements?
Yes, onChange works with <textarea> and <select> elements the same way it works with <input>. For <select>, event.target.value returns the value of the selected option. For <textarea>, it returns the text content.
How do I validate input with onChange?
Inside your onChange handler, you can add conditional logic to validate the input before updating state. For example, you could check if a value is a valid email format or if it meets a minimum length requirement before calling setState.
Why do I get a warning about switching between controlled and uncontrolled components?
This happens when you forget to initialize state with an empty string ('') or when you conditionally set the value prop. Always initialize your form state and always provide the value prop, even if you're updating it from undefined to a string.
Can I use onChange to prevent certain characters from being entered?
Yes, you can add validation logic in your onChange handler. For example, to allow only numbers, you could check if the new value is numeric before calling setInputValue. However, this approach requires careful handling to maintain good user experience.
Further Reading
Glossary
onChange: A React event handler that is triggered whenever the value of a form element (like<input>,<textarea>, or<select>) is changed by the user.- Controlled Component: A form element whose value is controlled by React state. The component's state is the "single source of truth," and the input's value is updated only when the state changes.
event.target.value: The property on the event object that contains the current value of the input element that triggered the event.- Synthetic Event: React's cross-browser wrapper around the browser's native event. It has the same interface as a browser event, including methods like
preventDefault()andstopPropagation().
➡️ Next Steps
You can now handle clicks and input changes, the two most common user interactions. In the next article, "Common Events: onSubmit (Part 3)", we will learn how to handle the submission of an entire form.
Thank you for your dedication. Stay curious, and happy coding!