表单校验与提交
表单校验与提交 · 阅读后完成下方实验与检查题,再用「标记完成」记录进度。
学习目标
玩具表单和真实表单的分水岭在提交之后:字段级校验、重复点击防护、服务端失败、成功反馈,一个都不能少。这一课把异步提交的完整生命周期补齐,读完你能写出一个「怎么折腾都不坏」的资料表单。
问题场景
个人资料表单第一版只有「校验通过就提交」两步:按钮没禁用,用户连点三次发出三个请求;服务端偶尔 500,页面直接白屏抛错;成功后没有反馈,用户不确定存没存上。这些都不是校验逻辑的问题,而是提交生命周期没有被完整建模。
核心解释
先把提交过程的状态数清楚:idle(可提交)→ submitting(请求中)→ saved(成功)或 error(失败,回到可改状态)。和 R05 一样,用互斥字段建模,天然排除「提交中和失败中并存」这类非法组合:
const [status, setStatus] = useState("idle");
const [fieldErrors, setFieldErrors] = useState({});
function validate() {
const errs = {};
if (!form.nickname.trim()) errs.nickname = "昵称必填";
if (!/^\S+@\S+\.\S+$/.test(form.email)) errs.email = "邮箱格式不对";
return errs;
}
async function handleSubmit(e) {
e.preventDefault();
const errs = validate();
setFieldErrors(errs);
if (Object.keys(errs).length > 0) return; // 校验不过不发请求
setStatus("submitting");
try {
await saveProfile(form);
setStatus("saved");
} catch {
setStatus("error");
}
}
四个细节撑起可靠性:
一、校验在客户端、拦截在提交入口。 字段错误存成 { 字段名: 消息 } 对象,渲染时按字段显示;校验不过直接 return,请求根本不发出。
二、重复点击防护。 submitting 期间按钮禁用并改文案——比在处理器里加 if 判断更直观,状态本身就是闸门:
<button type="submit" disabled={status === "submitting"}>
{status === "submitting" ? "保存中…" : "保存"}
</button>
{status === "saved" && <span>✅ 已保存</span>}
{status === "error" && <span>保存失败,请重试</span>}
三、服务端失败要可读、要保数据。 catch 里不能只 console.log:用户输入全部保留在受控 state 里(别清空表单),界面显示「保存失败,请重试」;如果是服务端返回的字段级错误(比如邮箱被占用),合并进 fieldErrors 显示到对应字段旁边。
四、成功要有反馈并落回稳态。 显示成功提示,几秒后或下次编辑时状态回到 idle,让表单可以继续被使用。
示例拆解
实验区是完整的资料表单,关键点如下:
- 字段:昵称(必填)、邮箱(格式校验)、简介(选填);错误信息显示在对应输入框下方,聚焦该字段时立刻可见;
- 三个模拟开关:「服务端失败」(500ms 后 reject)、「模拟慢网络」(2 秒延迟),配合提交按钮的禁用与文案变化,观察重复点击防护;
- 提交日志面板记录每次状态迁移:idle → submitting → error / saved,与界面显示一一对应;
- 服务端失败后输入内容原样保留,修正邮箱字段错误信息(「该邮箱已被注册」)来自服务端响应的模拟。
验证方式:开着「服务端失败」连点提交,请求不会叠加;关掉后一次成功,状态提示出现后自动回落。
动手任务
打开本课实验区,完成三个小改动:
- 简介字段加上限 50 字的校验,超限显示剩余字数提示。
- 成功后 3 秒自动回到 idle(用
setTimeout+ 清理),并支持「再次编辑」。 - 把「邮箱被注册」这类服务端字段错误合并进
fieldErrors,定位显示到邮箱下方。
常见错误
- 提交后清空表单再处理结果:失败时用户输入全丢;数据只在确认成功后才清理(本例的资料表单甚至不需要清)。
- 用布尔值防重复提交:
if (isSubmitting) return与按钮禁用双轨并行容易漏;让互斥的 status 字段做唯一闸门。 - catch 里吞掉错误细节:一律显示「出错了」让用户无从下手;区分网络错误与字段错误,字段错误要落到具体输入框旁。
- 校验放在 onChange 里每次输入都全量跑:用户第一个字还没打完就报错;字段级即时校验通常从字段失焦(onBlur)开始,提交时做全量校验。
检查与复盘
完成下方检查题确认理解。自查清单:
- 能画出提交状态机:idle / submitting / saved / error 及其迁移条件
- 重复点击、失败保数据、成功反馈三个可靠性细节都能说清实现位置
- 测试表单时会把失败、慢网络、连点三种情况都过一遍
参考资料
- React 官方文档:响应事件 —— 提交逻辑放在事件处理器里的依据
- MDN:客户端表单数据校验 —— 校验的通用背景知识
读完这一课了?
标记完成后,工作台会安排接下来的学习。