受控组件
表单元素(如 <input>、<textarea>、<select>)的值由 React 控制,称为受控组件。
基本示例
function NameForm() {
const [name, setName] = useState('');
const handleSubmit = (event) => {
alert('提交的名字: ' + name);
event.preventDefault();
};
return (
<form onSubmit={handleSubmit}>
<label>
名字:
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</label>
<button type="submit">提交</button>
</form>
);
}
textarea 标签
function EssayForm() {
const [value, setValue] = useState('请在此撰写文章...');
return (
<form>
<label>
文章:
<textarea
value={value}
onChange={(e) => setValue(e.target.value)}
rows={5}
cols={30}
/>
</label>
</form>
);
}
select 标签
function FlavorForm() {
const [flavor, setFlavor] = useState('coconut');
return (
<form>
<label>
选择你喜欢的口味:
<select value={flavor} onChange={(e) => setFlavor(e.target.value)}>
<option value="grapefruit">葡萄柚</option>
<option value="lime">酸橙</option>
<option value="coconut">椰子</option>
<option value="mango">芒果</option>
</select>
</label>
</form>
);
}
多个受控输入
function Reservation() {
const [formData, setFormData] = useState({
isGoing: true,
numberOfGuests: 2
});
const handleChange = (event) => {
const { name, value, type, checked } = event.target;
setFormData(prev => ({
...prev,
[name]: type === 'checkbox' ? checked : value
}));
};
return (
<form>
<label>
<input
name="isGoing"
type="checkbox"
checked={formData.isGoing}
onChange={handleChange}
/>
是否参加
</label>
<br />
<label>
来宾人数:
<input
name="numberOfGuests"
type="number"
value={formData.numberOfGuests}
onChange={handleChange}
/>
</label>
</form>
);
}
非受控组件
使用 ref 从 DOM 获取表单数据。
import { useRef } from 'react';
function ProfileForm() {
const nameRef = useRef(null);
const emailRef = useRef(null);
const handleSubmit = (e) => {
e.preventDefault();
console.log('名字:', nameRef.current.value);
console.log('邮箱:', emailRef.current.value);
};
return (
<form onSubmit={handleSubmit}>
<label>
名字:
<input
ref={nameRef}
type="text"
defaultValue="张三"
/>
</label>
<label>
邮箱:
<input
ref={emailRef}
type="email"
defaultValue="zhangsan@example.com"
/>
</label>
<button type="submit">提交</button>
</form>
);
}
文件上传
function FileInput() {
const fileInputRef = useRef(null);
const handleSubmit = (e) => {
e.preventDefault();
const files = fileInputRef.current.files;
console.log('选择的文件:', files);
};
return (
<form onSubmit={handleSubmit}>
<input
ref={fileInputRef}
type="file"
multiple
/>
<button type="submit">上传</button>
</form>
);
}
表单验证
实时验证
function ValidatedForm() {
const [email, setEmail] = useState('');
const [error, setError] = useState('');
const validateEmail = (email) => {
const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return re.test(email);
};
const handleChange = (e) => {
const value = e.target.value;
setEmail(value);
if (value && !validateEmail(value)) {
setError('请输入有效的邮箱地址');
} else {
setError('');
}
};
return (
<form>
<label>
邮箱:
<input
type="email"
value={email}
onChange={handleChange}
/>
{error && <p className="error">{error}</p>}
</label>
<button type="submit" disabled={!!error}>
提交
</button>
</form>
);
}
💡 最佳实践
- 优先使用受控组件:更好的控制和验证
- 使用 name 属性:简化表单处理逻辑
- 及时验证:提供即时反馈
- 处理文件上传:使用 FormData API
🎯 练习
- 创建一个完整的注册表单
- 实现搜索框组件
- 创建一个多步骤表单(wizard form)
下一节我们将学习 组件优化技巧!