01 · NOTES / WebGIS 开发
第 06 节 · 受控表单
2026 年 9 月 1 日
第 06 节 · 受控表单
📌 版本信息:React 19.x(2026-08-29 核对) 📚 来源:React 中文文档 · 用 State 响应输入 | React 中文文档 · 编辑表单
一、这一节的目标
- 精通受控组件:value + onChange 闭环
- 处理多字段表单:单 state 对象 + 计算属性名更新
- 掌握提交处理(preventDefault、校验、提交后重置)
- 完成搜索过滤表单——WebGIS 查询面板的标准形态
二、受控组件:React 是唯一事实来源
const [keyword, setKeyword] = useState('');
<input
value={keyword} // ① 界面显示 = state
onChange={(e) => setKeyword(e.target.value)} // ② 输入 → 更新 state
/> // ③ state 变 → 界面重渲染
// 三步闭环:输入框显示什么完全由 state 决定——所以叫"受控"
第 03 节已入门,本节解决真实表单的三个进阶问题:多字段、提交、校验。
三、多字段表单:一个 state 对象 + 计算属性名
const [form, setForm] = useState({ name: '', mag: 4, region: '华中' });
// 通用更新器:不用给每个字段写一个 handler
function update(field) {
return (e) => setForm({ ...form, [field]: e.target.value });
// ↑ 计算属性名(第 35 节):字段名动态决定
}
<input value={form.name} onChange={update('name')} />
<input type="number" value={form.mag} onChange={update('mag')} />
⚠️ 两个细节:①number 类型的输入,
e.target.value是字符串,记得Number();②checkbox 用e.target.checked。字段多且类型杂时,第 03 模块之后会引入 react-hook-form(第 11 节生态地图预告过),但手写受控是理解一切表单库的基础。
四、提交:校验 → 提交 → 重置
function handleSubmit(e) {
e.preventDefault(); // ① 阻止浏览器原生提交(刷新页面)
if (!form.name.trim()) { // ② 校验(不合格直接 return)
setError('地点必填');
return;
}
onSubmit({ ...form, id: crypto.randomUUID() }); // ③ 交数据(给父组件/发请求)
setForm(initialForm); // ④ 重置表单
}
<form onSubmit={handleSubmit}>…</form> // 用 onSubmit 而不是按钮 onClick(回车也能提交)
为什么用 form onSubmit 而不是 button onClick:原生表单语义(回车提交、无障碍)白拿;按钮单独写 onClick 会丢这些。
五、搜索过滤表单:查询面板的标准形态
WebGIS 查询面板的三要素,本节练习全覆盖:
// 数据源 + 两个筛选条件 + 派生结果(没有第二份数据!)
const [keyword, setKeyword] = useState('');
const [minMag, setMinMag] = useState(0);
const result = quakes
.filter((q) => q.properties.place.includes(keyword))
.filter((q) => q.properties.mag >= minMag);
// keyword/minMag 任一变化 → result 重新计算 → 列表自动正确
// (输入即过滤,无需"查询按钮"——这是受控表单的爽点)
六、动手跟练:06 · 搜索过滤表单
配套文件夹:03-react-nextjs/examples/06-搜索过滤表单/(npm i && npm run dev)
步骤:
- 需求:地震查询面板——关键字(地点模糊搜)+ 最低震级滑块 + 地区下拉 + 日期范围,四条件组合过滤,实时生效
- 完成 6 个 TODO:多字段 form state(计算属性名更新器)、滑块实时显示数值、组合过滤、空结果状态、重置按钮(恢复默认值)、提交式新增(把第 05 节的添加表单合并进来,走完整校验-提交-重置流程)
- 回归实验:把"实时过滤"改成"点查询按钮才过滤"——体会两种交互的差别(写 5 行注释说清何时该用哪种:数据量大/请求式查询时按钮更合理,预告第 04 节 useEffect + 防抖)
通关标准:
- 四条件组合过滤实时生效,互不干扰
- 能默写"一个 state 对象 + 计算属性名更新器"
- 能说出 form onSubmit 相比 button onClick 的两个好处
七、自测题
- 受控组件的三步闭环?
- 多字段表单为什么推荐"单 state 对象"而不是"每字段一个 useState"?
- number 输入框的 value 处理要注意什么?
- 提交处理函数的四步流程?
- "输入即过滤"什么时候不合适?
参考答案
- value 绑 state → onChange 更新 state → state 驱动重渲染。
- 提交时拿到完整表单对象、通用更新器少写一半代码、字段增删集中管理。
- e.target.value 是字符串,数字语义要 Number() 转换;范围用 min/max/step 约束。
- preventDefault → 校验 → 提交数据 → 重置表单。
- 数据量大(每次 keystroke 全量计算卡顿)或数据来自服务端(每次输入都打请求)——此时用"按钮触发"或"输入防抖 + useEffect"。
八、下一步
单组件玩明白了 → 第 07 节:组件通信,解决"兄弟组件怎么说话、跨层级怎么共享"。
TAGSweb