返回笔记列表
01 · NOTES / WebGIS 开发

第 06 节 · 受控表单

2026 年 9 月 1 日

第 06 节 · 受控表单

📌 版本信息:React 19.x(2026-08-29 核对) 📚 来源:React 中文文档 · 用 State 响应输入React 中文文档 · 编辑表单

一、这一节的目标

  1. 精通受控组件:value + onChange 闭环
  2. 处理多字段表单:单 state 对象 + 计算属性名更新
  3. 掌握提交处理(preventDefault、校验、提交后重置)
  4. 完成搜索过滤表单——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

步骤:

  1. 需求:地震查询面板——关键字(地点模糊搜)+ 最低震级滑块 + 地区下拉 + 日期范围,四条件组合过滤,实时生效
  2. 完成 6 个 TODO:多字段 form state(计算属性名更新器)、滑块实时显示数值、组合过滤、空结果状态、重置按钮(恢复默认值)、提交式新增(把第 05 节的添加表单合并进来,走完整校验-提交-重置流程)
  3. 回归实验:把"实时过滤"改成"点查询按钮才过滤"——体会两种交互的差别(写 5 行注释说清何时该用哪种:数据量大/请求式查询时按钮更合理,预告第 04 节 useEffect + 防抖)

通关标准:

  • 四条件组合过滤实时生效,互不干扰
  • 能默写"一个 state 对象 + 计算属性名更新器"
  • 能说出 form onSubmit 相比 button onClick 的两个好处

七、自测题

  1. 受控组件的三步闭环?
  2. 多字段表单为什么推荐"单 state 对象"而不是"每字段一个 useState"?
  3. number 输入框的 value 处理要注意什么?
  4. 提交处理函数的四步流程?
  5. "输入即过滤"什么时候不合适?

参考答案

  1. value 绑 state → onChange 更新 state → state 驱动重渲染。
  2. 提交时拿到完整表单对象、通用更新器少写一半代码、字段增删集中管理。
  3. e.target.value 是字符串,数字语义要 Number() 转换;范围用 min/max/step 约束。
  4. preventDefault → 校验 → 提交数据 → 重置表单。
  5. 数据量大(每次 keystroke 全量计算卡顿)或数据来自服务端(每次输入都打请求)——此时用"按钮触发"或"输入防抖 + useEffect"。

八、下一步

单组件玩明白了 → 第 07 节:组件通信,解决"兄弟组件怎么说话、跨层级怎么共享"。

TAGSweb