2215 字
11 分钟

React 表单处理

React 表单处理#

表单是Web应用中最常见的交互方式之一,用于收集用户输入的数据。在React中,表单处理与传统的HTML表单处理有所不同,React提供了受控组件和非受控组件两种方式来处理表单。

1. 受控组件#

受控组件是指表单元素的值由React的state控制的组件。在受控组件中,表单元素的值会与React的state保持同步,当用户输入时,会触发onChange事件,更新state,从而更新表单元素的值。

基本用法#

import React, { useState } from 'react';
function ControlledForm() {
// 初始化state
const [name, setName] = useState('');
const [email, setEmail] = useState('');
// 处理表单提交
const handleSubmit = (e) => {
e.preventDefault();
console.log('Name:', name);
console.log('Email:', email);
// 可以在这里进行表单验证、数据提交等操作
};
return (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="name">Name:</label>
<input
type="text"
id="name"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</div>
<div>
<label htmlFor="email">Email:</label>
<input
type="email"
id="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</div>
<button type="submit">Submit</button>
</form>
);
}

处理多个输入#

当表单中有多个输入字段时,可以使用一个对象来存储所有表单数据,简化代码。

import React, { useState } from 'react';
function MultiInputForm() {
// 使用对象存储表单数据
const [formData, setFormData] = useState({
name: '',
email: '',
password: ''
});
// 处理输入变化
const handleChange = (e) => {
const { name, value } = e.target;
setFormData(prevState => ({
...prevState,
[name]: value
}));
};
// 处理表单提交
const handleSubmit = (e) => {
e.preventDefault();
console.log('Form data:', formData);
// 可以在这里进行表单验证、数据提交等操作
};
return (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="name">Name:</label>
<input
type="text"
id="name"
name="name"
value={formData.name}
onChange={handleChange}
/>
</div>
<div>
<label htmlFor="email">Email:</label>
<input
type="email"
id="email"
name="email"
value={formData.email}
onChange={handleChange}
/>
</div>
<div>
<label htmlFor="password">Password:</label>
<input
type="password"
id="password"
name="password"
value={formData.password}
onChange={handleChange}
/>
</div>
<button type="submit">Submit</button>
</form>
);
}

处理复选框和单选按钮#

复选框和单选按钮的处理与文本输入框略有不同,需要处理checked属性而不是value属性。

import React, { useState } from 'react';
function CheckboxAndRadioForm() {
// 初始化state
const [isSubscribed, setIsSubscribed] = useState(false);
const [gender, setGender] = useState('male');
// 处理表单提交
const handleSubmit = (e) => {
e.preventDefault();
console.log('Is subscribed:', isSubscribed);
console.log('Gender:', gender);
};
return (
<form onSubmit={handleSubmit}>
<div>
<label>
<input
type="checkbox"
checked={isSubscribed}
onChange={(e) => setIsSubscribed(e.target.checked)}
/>
Subscribe to newsletter
</label>
</div>
<div>
<label>Gender:</label>
<div>
<label>
<input
type="radio"
name="gender"
value="male"
checked={gender === 'male'}
onChange={(e) => setGender(e.target.value)}
/>
Male
</label>
<label>
<input
type="radio"
name="gender"
value="female"
checked={gender === 'female'}
onChange={(e) => setGender(e.target.value)}
/>
Female
</label>
<label>
<input
type="radio"
name="gender"
value="other"
checked={gender === 'other'}
onChange={(e) => setGender(e.target.value)}
/>
Other
</label>
</div>
</div>
<button type="submit">Submit</button>
</form>
);
}

处理下拉菜单#

下拉菜单的处理与文本输入框类似,需要处理value属性和onChange事件。

import React, { useState } from 'react';
function SelectForm() {
// 初始化state
const [country, setCountry] = useState('');
// 处理表单提交
const handleSubmit = (e) => {
e.preventDefault();
console.log('Country:', country);
};
return (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="country">Country:</label>
<select
id="country"
value={country}
onChange={(e) => setCountry(e.target.value)}
>
<option value="">Select a country</option>
<option value="usa">United States</option>
<option value="canada">Canada</option>
<option value="uk">United Kingdom</option>
<option value="china">China</option>
<option value="japan">Japan</option>
</select>
</div>
<button type="submit">Submit</button>
</form>
);
}

2. 非受控组件#

非受控组件是指表单元素的值由DOM本身控制的组件。在非受控组件中,React不跟踪表单元素的值,而是通过ref来获取表单元素的值。

基本用法#

import React, { useRef } from 'react';
function UncontrolledForm() {
// 创建ref
const nameRef = useRef(null);
const emailRef = useRef(null);
// 处理表单提交
const handleSubmit = (e) => {
e.preventDefault();
console.log('Name:', nameRef.current.value);
console.log('Email:', emailRef.current.value);
// 可以在这里进行表单验证、数据提交等操作
};
return (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="name">Name:</label>
<input
type="text"
id="name"
ref={nameRef}
/>
</div>
<div>
<label htmlFor="email">Email:</label>
<input
type="email"
id="email"
ref={emailRef}
/>
</div>
<button type="submit">Submit</button>
</form>
);
}

默认值#

在非受控组件中,可以使用defaultValue属性来设置表单元素的默认值,而不是value属性。

import React, { useRef } from 'react';
function UncontrolledFormWithDefault() {
// 创建ref
const nameRef = useRef(null);
const emailRef = useRef(null);
// 处理表单提交
const handleSubmit = (e) => {
e.preventDefault();
console.log('Name:', nameRef.current.value);
console.log('Email:', emailRef.current.value);
// 可以在这里进行表单验证、数据提交等操作
};
return (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="name">Name:</label>
<input
type="text"
id="name"
ref={nameRef}
defaultValue="John Doe"
/>
</div>
<div>
<label htmlFor="email">Email:</label>
<input
type="email"
id="email"
ref={emailRef}
defaultValue="john@example.com"
/>
</div>
<button type="submit">Submit</button>
</form>
);
}

3. 受控组件与非受控组件的比较#

特性受控组件非受控组件
数据存储React stateDOM
数据获取从state中获取通过ref获取
实时验证支持不支持
动态表单值支持不支持
性能可能较低(每次输入都会触发重新渲染)较高(不会触发重新渲染)
代码复杂度较高较低

4. 表单验证#

表单验证是确保用户输入数据有效性的重要步骤。在React中,可以在受控组件的onChange事件中进行实时验证,也可以在表单提交时进行验证。

实时验证#

import React, { useState } from 'react';
function ValidatedForm() {
const [formData, setFormData] = useState({
name: '',
email: ''
});
const [errors, setErrors] = useState({
name: '',
email: ''
});
// 验证函数
const validate = (name, value) => {
let error = '';
if (name === 'name') {
if (!value) {
error = 'Name is required';
} else if (value.length < 3) {
error = 'Name must be at least 3 characters';
}
} else if (name === 'email') {
if (!value) {
error = 'Email is required';
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
error = 'Email is invalid';
}
}
return error;
};
// 处理输入变化
const handleChange = (e) => {
const { name, value } = e.target;
// 更新表单数据
setFormData(prevState => ({
...prevState,
[name]: value
}));
// 验证输入
const error = validate(name, value);
// 更新错误信息
setErrors(prevState => ({
...prevState,
[name]: error
}));
};
// 处理表单提交
const handleSubmit = (e) => {
e.preventDefault();
// 验证所有字段
const nameError = validate('name', formData.name);
const emailError = validate('email', formData.email);
// 更新错误信息
setErrors({
name: nameError,
email: emailError
});
// 如果没有错误,提交表单
if (!nameError && !emailError) {
console.log('Form submitted:', formData);
}
};
return (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="name">Name:</label>
<input
type="text"
id="name"
name="name"
value={formData.name}
onChange={handleChange}
/>
{errors.name && <p style={{ color: 'red' }}>{errors.name}</p>}
</div>
<div>
<label htmlFor="email">Email:</label>
<input
type="email"
id="email"
name="email"
value={formData.email}
onChange={handleChange}
/>
{errors.email && <p style={{ color: 'red' }}>{errors.email}</p>}
</div>
<button type="submit">Submit</button>
</form>
);
}

5. 表单库#

对于复杂的表单,使用第三方表单库可以大大简化开发过程。以下是一些常用的React表单库:

Formik#

Formik是一个用于构建表单的React库,提供了表单状态管理、验证、错误处理等功能。

import React from 'react';
import { Formik, Form, Field, ErrorMessage } from 'formik';
import * as Yup from 'yup';
// 定义验证模式
const validationSchema = Yup.object({
name: Yup.string()
.required('Name is required')
.min(3, 'Name must be at least 3 characters'),
email: Yup.string()
.required('Email is required')
.email('Email is invalid')
});
function FormikForm() {
return (
<Formik
initialValues={{ name: '', email: '' }}
validationSchema={validationSchema}
onSubmit={(values) => {
console.log('Form submitted:', values);
}}
>
<Form>
<div>
<label htmlFor="name">Name:</label>
<Field type="text" id="name" name="name" />
<ErrorMessage name="name" component="p" style={{ color: 'red' }} />
</div>
<div>
<label htmlFor="email">Email:</label>
<Field type="email" id="email" name="email" />
<ErrorMessage name="email" component="p" style={{ color: 'red' }} />
</div>
<button type="submit">Submit</button>
</Form>
</Formik>
);
}

React Hook Form#

React Hook Form是一个基于Hook的表单库,提供了轻量级、高性能的表单处理方案。

import React from 'react';
import { useForm } from 'react-hook-form';
function ReactHookForm() {
const { register, handleSubmit, formState: { errors } } = useForm();
const onSubmit = (data) => {
console.log('Form submitted:', data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<label htmlFor="name">Name:</label>
<input
type="text"
id="name"
{...register('name', { required: 'Name is required', minLength: { value: 3, message: 'Name must be at least 3 characters' } })}
/>
{errors.name && <p style={{ color: 'red' }}>{errors.name.message}</p>}
</div>
<div>
<label htmlFor="email">Email:</label>
<input
type="email"
id="email"
{...register('email', { required: 'Email is required', pattern: { value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, message: 'Email is invalid' } })}
/>
{errors.email && <p style={{ color: 'red' }}>{errors.email.message}</p>}
</div>
<button type="submit">Submit</button>
</form>
);
}

6. 最佳实践#

  1. 优先使用受控组件:受控组件可以更好地与React的state管理集成,支持实时验证和动态表单值。
  2. 使用对象存储表单数据:当表单中有多个输入字段时,使用一个对象来存储所有表单数据,简化代码。
  3. 使用表单验证:确保用户输入的数据有效性,提高应用的可靠性。
  4. 使用第三方表单库:对于复杂的表单,使用第三方表单库可以大大简化开发过程。
  5. 考虑性能:对于大型表单或频繁输入的场景,考虑使用useCallback缓存事件处理函数,或使用非受控组件提高性能。
  6. 保持表单逻辑清晰:将表单逻辑与UI组件分离,提高代码的可维护性。

练习#

  1. 创建一个登录表单,包含用户名和密码字段,支持表单验证。
  2. 创建一个注册表单,包含用户名、邮箱、密码和确认密码字段,支持表单验证。
  3. 创建一个包含复选框、单选按钮和下拉菜单的表单。
  4. 使用Formik或React Hook Form创建一个复杂的表单。

总结#

在本章节中,我们学习了React中的表单处理方法和最佳实践,包括:

  • 受控组件:表单元素的值由React的state控制
  • 非受控组件:表单元素的值由DOM本身控制
  • 处理不同类型的表单输入:文本输入框、复选框、单选按钮、下拉菜单
  • 表单验证:实时验证和提交时验证
  • 第三方表单库:Formik和React Hook Form
  • 最佳实践:优先使用受控组件、使用对象存储表单数据、使用表单验证等

表单处理是React开发中的一个重要内容,掌握这些方法和最佳实践将帮助你构建更加可靠、用户友好的表单。

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

React 表单处理
https://firefly.cuteleaf.cn/posts/react/05-react-forms/
作者
Lireal
发布于
2026-01-21
许可协议
CC BY-NC-SA 4.0

目录