Kodokon kodokon.com

受控表单

学习通过 React 状态驱动每一个表单字段,从而校验并提交可靠的数据。

8 分钟 · 3 题

在 Kodokon 中打开本课

在 React 中,当每个字段都是受控的时,表单就变得可预测:显示的值来自组件的状态,每一次按键都通过 onChange 来更新该状态。DOM 不再是数据的唯一来源,你的状态才是。实际操作中,你把 value 属性绑定到一个状态变量上,并提供一个调用更新函数的处理器。

JSX
import { useState } from "react";

function EmailField() {
  const [email, setEmail] = useState("");

  return (
    <input
      type="email"
      value={email}
      onChange={(e) => setEmail(e.target.value)}
    />
  );
}
一个受控字段:value 读取状态,onChange 写入状态。

真实的表单很少只有一个字段。与其堆叠多个 useState 调用,不如把这些值归并到一个对象中,并编写一个通用处理器。每个字段的 name 属性必须与对象的某个键完全对应:正是它告诉处理器要更新哪个属性。

JSX
const [form, setForm] = useState({
  username: "",
  password: "",
});

function handleChange(e) {
  const { name, value } = e.target;
  setForm((prev) => ({ ...prev, [name]: value }));
}
一个处理器搞定表单中的每一个字段。

剩下的就是提交了。默认情况下,提交表单时浏览器会重新加载页面:请在 onSubmit 处理器的开头调用 e.preventDefault()。这里也是在发送数据前校验数据的恰当位置,因为整个表单状态已经就在手边。

JSX
function handleSubmit(e) {
  e.preventDefault();
  if (form.username.trim() === "") {
    alert("Username is required.");
    return;
  }
  console.log("Submitting:", form);
}

return (
  <form onSubmit={handleSubmit}>
    <input
      name="username"
      value={form.username}
      onChange={handleChange}
    />
    <button type="submit">Create account</button>
  </form>
);
先校验,再提交,且不重新加载页面。

知识检测

确认你已牢记本课的重点内容。

  1. 在 React 中,什么定义了一个受控字段?
    • 它的值存储在 DOM 中,并通过 ref 读取
    • 它的值来自状态,且每一次按键都通过 onChange
    • 在表单提交之前它都是只读的
    • 它会自动校验你输入的数据
  2. 你给一个 <input> 传了 value={email},却没有提供 onChange。会发生什么?
    • 字段被冻结:再输入也没有任何效果
    • 字段正常工作,React 会自行处理输入
    • 组件在首次渲染时崩溃
  3. onSubmit 处理器中,e.preventDefault() 有什么用?
    • 阻止原生表单提交所触发的页面重新加载
    • 自动清空表单字段
    • 阻止事件向父组件传播
    • 禁用浏览器的 HTML 校验