====== 第十章:表单处理 ======
===== 10.1 受控组件 =====
在 HTML 中,表单元素如 input、textarea、select 通常自己维护 state。在 React 中,可变状态通常保存在组件的 state 中,只能用 setState 更新。
**输入框**:
function NameForm() {
const [value, setValue] = useState('');
const handleChange = (e) => {
setValue(e.target.value);
};
const handleSubmit = (e) => {
e.preventDefault();
alert('提交的名字: ' + value);
};
return (
;
);
}
**文本域**:
function EssayForm() {
const [value, setValue] = useState('请撰写关于你喜欢的事物的文章');
const handleChange = (e) => {
setValue(e.target.value);
};
return (
;
);
}
**下拉选择**:
function FlavorForm() {
const [value, setValue] = useState('coconut');
const handleChange = (e) => {
setValue(e.target.value);
};
const handleSubmit = (e) => {
e.preventDefault();
alert('你喜欢的风味是: ' + value);
};
return (
;
);
}
**多选**:
function MultipleSelect() {
const [values, setValues] = useState(['coconut']);
const handleChange = (e) => {
const options = e.target.options;
const selected = [];
for (let i = 0; i < options.length; i++) {
if (options[i].selected) {
selected.push(options[i].value);
}
}
setValues(selected);
};
return (
;
);
}
===== 10.2 处理多个输入 =====
function ReservationForm() {
const [state, setState] = useState({
isGoing: true,
numberOfGuests: 2
});
const handleChange = (e) => {
const { name, type, checked, value } = e.target;
setState({
...state,
[name]: type === 'checkbox' ? checked : value
});
};
return (
;
);
}
===== 10.3 非受控组件 =====
非受控组件将表单数据存储在 DOM 中,而不是组件 state。
function NameForm() {
const inputRef = useRef(null);
const handleSubmit = (e) => {
e.preventDefault();
alert('Name: ' + inputRef.current.value);
};
return (
;
);
}
**默认值**:
function Form() {
return (
;
);
}
**文件输入**:
文件 input 始终是非受控组件,因为它的值只能由用户设置。
function FileInput() {
const fileInput = useRef(null);
const handleSubmit = (e) => {
e.preventDefault();
const file = fileInput.current.files[0];
alert(`Selected file - ${file.name}`);
};
return (
;
);
}
===== 10.4 表单验证 =====
**即时验证**:
function ValidationForm() {
const [email, setEmail] = useState('');
const [error, setError] = useState('');
const validateEmail = (value) => {
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return regex.test(value);
};
const handleChange = (e) => {
const value = e.target.value;
setEmail(value);
if (value && !validateEmail(value)) {
setError('请输入有效的邮箱地址');
} else {
setError('');
}
};
return (
;
);
}
**提交时验证**:
function FormWithValidation() {
const [values, setValues] = useState({ email: '', password: '' });
const [errors, setErrors] = useState({});
const validate = () => {
const newErrors = {};
if (!values.email) {
newErrors.email = '邮箱必填';
} else if (!/\S+@\S+\.\S+/.test(values.email)) {
newErrors.email = '邮箱格式不正确';
}
if (!values.password) {
newErrors.password = '密码必填';
} else if (values.password.length < 6) {
newErrors.password = '密码至少 6 位';
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
const handleSubmit = (e) => {
e.preventDefault();
if (validate()) {
// 提交表单
}
};
return (
;
);
}
===== 10.5 使用表单库 =====
**React Hook Form**:
npm install react-hook-form
import { useForm } from 'react-hook-form';
function HookFormExample() {
const { register, handleSubmit, formState: { errors } } = useForm();
const onSubmit = data => console.log(data);
return (
;
);
}
**Formik**:
npm install formik yup
import { Formik, Form, Field, ErrorMessage } from 'formik';
import * as Yup from 'yup';
const schema = Yup.object({
email: Yup.string().email('邮箱格式不正确').required('邮箱必填'),
password: Yup.string().min(6, '密码至少 6 位').required('密码必填')
});
function FormikExample() {
return (
console.log(values)}
>
{}
;
);
}
===== 10.6 总结 =====
本章详细介绍了表单处理:
* 受控组件
* 非受控组件
* 处理多个输入
* 表单验证
* 常用表单库
表单是 Web 应用的核心,掌握这些技巧可以大大提高开发效率。