10. Building Forms with Controlled Components
Level: BeginnerDuration: 20m
What Are Controlled Components?
In React, controlled components are form elements like inputs and textareas that are controlled by React state. This means the displayed value always comes from state.
jsx
<input value={name} onChange={handleChange} />This input is controlled because its value is managed by React.
Managing Form State with useState
We use the useState hook to track form input values.
jsx
import { useState } from 'react'
function FormExample() {
const [name, setName] = useState('')
function handleChange(e) {
setName(e.target.value)
}
return (
<input type="text" value={name} onChange={handleChange} />
)
}Handling Form Submission
React forms use the onSubmit event. We usually prevent the default browser refresh.
jsx
function FormExample() {
const [name, setName] = useState('')
function handleSubmit(e) {
e.preventDefault()
console.log('Submitted:', name)
}
return (
<form onSubmit={handleSubmit}>
<input value={name} onChange={e => setName(e.target.value)} />
<button type="submit">Submit</button>
</form>
)
}Handling Multiple Inputs
We can manage multiple fields using a single state object.
jsx
function SignupForm() {
const [formData, setFormData] = useState({ name: '', email: '' })
function handleChange(e) {
setFormData({ ...formData, [e.target.name]: e.target.value })
}
return (
<form>
<input name="name" value={formData.name} onChange={handleChange} />
<input name="email" value={formData.email} onChange={handleChange} />
</form>
)
}Controlled vs Uncontrolled Components
Controlled components use useState to manage values. Uncontrolled components use refs and access values directly from the DOM. Controlled components give us more control and are preferred for most forms.
Mini Project Step
Add a simple feature input form to your project so users can add new features to the feature list.
jsx
// App.jsx
import { useState } from 'react'
function App() {
const [features, setFeatures] = useState(['Reusable components', 'Fast rendering'])
const [newFeature, setNewFeature] = useState('')
function handleSubmit(e) {
e.preventDefault()
if (!newFeature.trim()) return
setFeatures([...features, newFeature])
setNewFeature('')
}
return (
<div>
<h1>Project Features</h1>
<form onSubmit={handleSubmit}>
<input
type="text"
value={newFeature}
onChange={e => setNewFeature(e.target.value)}
placeholder="Add a new feature"
/>
<button type="submit">Add Feature</button>
</form>
<ul>
{features.map((feature, index) => (
<li key={index}>{feature}</li>
))}
</ul>
</div>
)
}
export default App