React学习教程,从入门到精通,React 表单完整语法知识点与使用方法(22)
React 表单完整语法知识点与使用方法
一、使用表单(Form in React)
React 中使用表单与原生 HTML 类似,但数据流是“单向绑定”,推荐使用“受控组件”管理表单状态。
✅ 语法要点:
- 使用
<form>
标签包裹表单元素 - 使用
onSubmit
事件代替原生submit
,防止页面刷新 - 推荐使用
e.preventDefault()
阻止默认提交行为
🧩 示例代码:
import React, { useState } from 'react';function LoginForm() {const [username, setUsername] = useState('');// 表单提交处理函数const handleSubmit = (e) => {e.preventDefault(); // 阻止页面刷新alert(`提交的用户名是:${username}`);};return (<form onSubmit={handleSubmit}><label>用户名:<inputtype="text"value={username}onChange={(e) => setUsername(e.target.value)}/></label><br /><button type="submit">提交</button></form>);
}export default LoginForm;
💡 注释说明:
useState
用于管理输入值onChange
实时更新状态onSubmit
捕获提交事件,避免刷新
二、表单元素(Form Elements)
React 支持所有 HTML 表单元素:<input>
, <textarea>
, <select>
, <button>
等。
✅ 语法要点:
- 所有表单元素必须绑定
value
(受控)或defaultValue
(非受控) onChange
是监听值变化的核心事件type
属性决定输入类型(text, password, checkbox, radio, file 等)
🧩 示例代码:
import React, { useState } from 'react';function FormElementsDemo() {const [formData, setFormData] = useState({name: '',bio: '',gender: 'male',newsletter: false,});const handleChange = (e) => {const { name, value, type, checked } = e.target;setFormData({...formData,[name]: type === 'checkbox' ? checked : value,});};return (<form>{/* 文本输入 */}<div><label>姓名:</label><inputtype="text"name="name"value={formData.name}onChange={handleChange}/></div>{/* 多行文本 */}<div><label>简介:</label><textareaname="bio"value={formData.bio}onChange={handleChange}/></div>{/* 单选按钮 */}<div><label>性别:</label><label><inputtype="radio"name="gender"value="male"checked={formData.gender === 'male'}onChange={handleChange}/>男</label><label><inputtype="radio"name="gender"value="female"checked={formData.gender === 'female'}onChange={handleChange}/>女</label></div>{/* 复选框 */}<div><label><inputtype="checkbox"name="newsletter"checked={formData.newsletter}onChange={handleChange}/>订阅新闻</label></div></form>);
}export default FormElementsDemo;
💡 注释说明:
- 使用对象管理多个字段,避免重复声明 state
- 使用
[name]
动态设置键名- checkbox 和 radio 需要特殊处理
checked
属性
三、事件响应(Event Handling)
React 事件使用驼峰命名法(如 onClick
),且传递的是合成事件对象。
✅ 语法要点:
- 事件处理器是函数,不能直接调用(不要加括号)
- 使用箭头函数或
bind
绑定this
(在 class 组件中) - 推荐在构造函数或使用类字段语法绑定
🧩 示例代码(Class Component):
import React, { Component } from 'react';class EventDemo extends Component {constructor(props) {super(props);this.state = { count: 0 };// 方法一:在构造函数中 bindthis.handleClick = this.handleClick.bind(this);}// 方法二:使用箭头函数自动绑定 this(推荐)handleIncrement = () => {this.setState({ count: this.state.count + 1 });};// 方法三:在 render 中使用箭头函数(不推荐,性能差)handleClick() {this.setState({ count: this.state.count - 1 });}render() {return (<div><p>当前计数:{this.state.count}</p><button onClick={this.handleIncrement}>+1(箭头函数)</button><button onClick={this.handleClick}>-1(bind 绑定)</button><button onClick={() => this.setState({ count: 0 })}>重置(内联箭头)</button></div>);}
}export default EventDemo;
💡 注释说明:
bind(this)
在构造函数中绑定,避免每次渲染重新绑定- 箭头函数自动绑定
this
,是现代 React 推荐写法- 内联箭头函数每次渲染都会创建新函数,影响性能
四、bind 复用(Reusing bind)
在 class 组件中,为多个元素绑定相同事件处理器时,可以复用 bind
传参。
✅ 语法要点:
- 使用
bind
传递额外参数(如索引、ID) - 避免在 render 中创建新函数
🧩 示例代码:
import React, { Component } from 'react';class BindReuseDemo extends Component {constructor(props) {super(props);this.state = {items: ['苹果', '香蕉', '橙子'],};this.handleClick = this.handleClick.bind(this);}handleClick(index, e) {e.preventDefault();alert(`点击了第 ${index + 1} 项:${this.state.items[index]}`);}render() {return (<ul>{this.state.items.map((item, index) => (<li key={index}>{item}{/* 复用 handleClick,通过 bind 传参 */}<button onClick={this.handleClick.bind(this, index)}>点击我</button></li>))}</ul>);}
}export default BindReuseDemo;
💡 注释说明:
bind(this, index)
将index
作为第一个参数传入- 事件对象
e
会作为后续参数传入- 避免使用内联箭头函数如
onClick={() => this.handleClick(index)}
,影响性能
五、name 复用(Reusing name attribute)
通过 name
属性统一处理多个表单控件,实现“动态键名”更新状态。
✅ 语法要点:
- 所有表单元素设置
name
属性 - 事件处理器中通过
e.target.name
获取字段名 - 使用计算属性名
[name]
更新对应状态
🧩 示例代码:
import React, { useState } from 'react';function NameReuseDemo() {const [user, setUser] = useState({firstName: '',lastName: '',email: '',});const handleChange = (e) => {const { name, value } = e.target;setUser((prev) => ({...prev,[name]: value, // 动态键名,复用 name}));};const handleSubmit = (e) => {e.preventDefault();console.log('用户信息:', user);};return (<form onSubmit={handleSubmit}><inputname="firstName"placeholder="名"value={user.firstName}onChange={handleChange}/><inputname="lastName"placeholder="姓"value={user.lastName}onChange={handleChange}/><inputname="email"placeholder="邮箱"value={user.email}onChange={handleChange}/><button type="submit">提交</button></form>);
}export default NameReuseDemo;
💡 注释说明:
name
与 state 键名一致,实现自动映射[name]: value
是 ES6 计算属性语法- 极大减少重复代码,提高可维护性
六、可控组件(Controlled Components)
表单数据由 React state 控制,称为“受控组件”。
✅ 语法要点:
- 表单元素的
value
绑定 state onChange
更新 state- 完全控制输入行为(如格式化、校验)
🧩 示例代码:
import React, { useState } from 'react';function ControlledComponent() {const [input, setInput] = useState('');const handleChange = (e) => {// 可加入格式化或校验逻辑const value = e.target.value.toUpperCase(); // 强制大写setInput(value);};return (<div><inputtype="text"value={input} // 受控:值来自 stateonChange={handleChange}placeholder="输入内容会转为大写"/><p>当前值:{input}</p></div>);
}export default ControlledComponent;
💡 注释说明:
- 输入内容被 React 完全控制
- 可实时校验、格式化、限制输入
- 是 React 推荐的表单处理方式
七、不可控组件(Uncontrolled Components)
表单数据由 DOM 自己管理,通过 ref
获取值。
✅ 语法要点:
- 使用
defaultValue
或defaultChecked
- 使用
useRef
创建引用 - 适合文件上传、集成非 React 库等场景
🧩 示例代码:
import React, { useRef } from 'react';function UncontrolledComponent() {const inputRef = useRef(null);const handleSubmit = (e) => {e.preventDefault();alert(`输入的值是:${inputRef.current.value}`);inputRef.current.value = ''; // 手动清空};return (<form onSubmit={handleSubmit}><inputtype="text"defaultValue="默认值"ref={inputRef} // 不受控,通过 ref 获取值/><button type="submit">提交</button></form>);
}export default UncontrolledComponent;
💡 注释说明:
defaultValue
设置初始值,后续由 DOM 管理useRef
获取真实 DOM 元素- 适用于迁移旧代码或特定场景(如
<input type="file">
)
八、本章小结(Summary)
知识点 | 核心思想 | 推荐场景 |
---|---|---|
表单使用 | onSubmit + preventDefault | 所有表单 |
表单元素 | 受控绑定 value + onChange | 输入、选择、文本域 |
事件响应 | 箭头函数或构造函数 bind | 按钮、表单、列表项 |
bind 复用 | bind(this, param) 传参 | 列表操作、动态事件 |
name 复用 | [e.target.name] 动态更新 state | 多字段表单 |
可控组件 | 完全由 React state 控制 | 大部分表单(推荐) |
不可控组件 | 通过 ref 操作 DOM | 文件上传、第三方集成 |
✅ 最佳实践建议:
- 优先使用 受控组件
- 使用
name
+ 对象 state 管理多字段- 避免在 render 中使用内联箭头函数
- 复杂表单可使用
useReducer
或表单库(如 Formik、React Hook Form)
🎯 综合性实战案例
案例一:用户注册表单(受控 + 校验 + 提交)
import React, { useState } from 'react';function RegisterForm() {const [formData, setFormData] = useState({username: '',email: '',password: '',agree: false,});const [errors, setErrors] = useState({});const handleChange = (e) => {const { name, value, type, checked } = e.target;setFormData({...formData,[name]: type === 'checkbox' ? checked : value,});// 清除对应错误if (errors[name]) {setErrors((prev) => ({ ...prev, [name]: '' }));}};const validate = () => {const newErrors = {};if (!formData.username) newErrors.username = '用户名不能为空';if (!/\S+@\S+\.\S+/.test(formData.email)) newErrors.email = '邮箱格式不正确';if (formData.password.length < 6) newErrors.password = '密码至少6位';if (!formData.agree) newErrors.agree = '必须同意条款';return newErrors;};const handleSubmit = (e) => {e.preventDefault();const newErrors = validate();if (Object.keys(newErrors).length > 0) {setErrors(newErrors);} else {alert('注册成功!数据:' + JSON.stringify(formData, null, 2));// 提交到服务器...}};return (<form onSubmit={handleSubmit} style={{ maxWidth: '400px', margin: '0 auto' }}><div><label>用户名:</label><inputname="username"value={formData.username}onChange={handleChange}/>{errors.username && <span style={{ color: 'red' }}> {errors.username}</span>}</div><div><label>邮箱:</label><inputname="email"type="email"value={formData.email}onChange={handleChange}/>{errors.email && <span style={{ color: 'red' }}> {errors.email}</span>}</div><div><label>密码:</label><inputname="password"type="password"value={formData.password}onChange={handleChange}/>{errors.password && <span style={{ color: 'red' }}> {errors.password}</span>}</div><div><label><inputname="agree"type="checkbox"checked={formData.agree}onChange={handleChange}/>我同意用户条款</label>{errors.agree && <span style={{ color: 'red' }}> {errors.agree}</span>}</div><button type="submit" style={{ marginTop: '10px' }}>注册</button></form>);
}export default RegisterForm;
案例二:动态表单项(bind复用 + name复用 + 受控)
import React, { useState } from 'react';function DynamicForm() {const [items, setItems] = useState([{ id: 1, name: '项目1', value: '' },{ id: 2, name: '项目2', value: '' },]);const handleItemChange = (id, e) => {const { value } = e.target;setItems(items.map((item) =>item.id === id ? { ...item, value } : item));};const addItem = () => {const newId = items.length > 0 ? Math.max(...items.map(i => i.id)) + 1 : 1;setItems([...items, { id: newId, name: `项目${newId}`, value: '' }]);};const handleSubmit = (e) => {e.preventDefault();console.log('提交数据:', items);};return (<form onSubmit={handleSubmit}>{items.map((item) => (<div key={item.id}><label>{item.name}:</label><inputtype="text"value={item.value}onChange={handleItemChange.bind(null, item.id)} // bind 传 id/></div>))}<button type="button" onClick={addItem}>添加项目</button><button type="submit">提交</button></form>);
}export default DynamicForm;
案例三:混合受控与非受控(文件上传)
import React, { useState, useRef } from 'react';function MixedForm() {const [username, setUsername] = useState('');const fileInputRef = useRef(null);const handleSubmit = (e) => {e.preventDefault();const file = fileInputRef.current.files[0];alert(`用户名:${username},文件:${file ? file.name : '无'}`);};return (<form onSubmit={handleSubmit}><div><label>用户名(受控):</label><inputtype="text"value={username}onChange={(e) => setUsername(e.target.value)}/></div><div><label>上传文件(非受控):</label><input type="file" ref={fileInputRef} /></div><button type="submit">提交</button></form>);
}export default MixedForm;
✅ 至此,你已掌握 React 表单开发的全部核心知识点与实战技巧!
如需进一步学习,可探索:
useReducer
管理复杂表单状态- React Hook Form / Formik 表单库
- 表单异步校验、防抖提交等高级技巧