人人都会AI编程

3.6 前馈神经网络(FFN)、层归一化、残差连接的作用

更新时间:2026-07-10

表单是 Web 应用中最常见的交互形式,React 处理表单的方式与原生 HTML 存在关键差异。理解受控组件与非受控组件的区别,是掌握 React 表单开发的基础。

受控组件(Controlled Components)

受控组件是指表单元素的值由 React 的 state 统一管理,并通过事件处理函数更新 state。React 成为状态的“唯一数据源”,表单输入、状态、视图三者保持严格同步。

function ControlledForm() {
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log('提交数据:', { name, email });
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        value={name}
        onChange={(e) => setName(e.target.value)}
        placeholder="姓名"
      />
      <input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="邮箱"
      />
      <button type="submit">提交</button>
    </form>
  );
}

工作流程:用户输入 → 触发 onChange → 更新 state → React 重新渲染组件,value 属性同步最新值。

受控组件的优势

  • 数据实时可用:state 始终持有最新值,无需手动读取 DOM。
  • 灵活控制输入:可以在 onChange 中格式化数据(如自动去除空格、限制字符数)。
  • 表单验证便捷:实时校验输入并动态显示错误信息。
  • 条件渲染依赖:表单状态可直接驱动其他 UI 变化。

常见模式:实时格式化输入

<input
  type="text"
  value={name}
  onChange={(e) => setName(e.target.value.toUpperCase())}
/>

用户输入自动转为大写,一切在 React 控制之中。

非受控组件(Uncontrolled Components)

非受控组件是指表单元素的值由 DOM 自身维护,React 不直接管理其状态。需要时通过 ref 从 DOM 节点读取当前值,而非通过 state 驱动。

function UncontrolledForm() {
  const nameRef = useRef(null);
  const emailRef = useRef(null);

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log('提交数据:', {
      name: nameRef.current.value,
      email: emailRef.current.value,
    });
  };

  return (
    <form onSubmit={handleSubmit}>
      <input type="text" ref={nameRef} placeholder="姓名" defaultValue="张三" />
      <input type="email" ref={emailRef} placeholder="邮箱" />
      <button type="submit">提交</button>
    </form>
  );
}

关键点

  • 使用 ref 代替 value + onChange
  • 初始值通过 defaultValue(或 defaultChecked)设置,而不是 value
  • 数据只在需要时(如提交表单)读取,不会每次输入都触发渲染。

非受控组件的适用场景

  • 简单表单,不需要实时校验或格式化。
  • 需要集成非 React 代码(如第三方 DOM 库)。
  • 性能敏感场景,避免频繁重渲染(React 18 的自动批处理已缓解大部分情况)。

受控 vs 非受控:如何选择

| 特性 | 受控组件 | 非受控组件 |
|------|----------|------------|
| 数据源 | React state | DOM 节点 |
| 实时数据访问 | 是,state 始终最新 | 否,需要时读取 |
| 代码量 | 较多(value + onChange) | 较少(ref) |
| 表单验证 | 实时校验,易实现 | 提交时校验为主 |
| 性能 | 每次输入触发重渲染 | 仅在需要时读取,不触发额外渲染 |
| 推荐度 | 首选方案,React 官方推荐 | 特定场景或快速原型 |

实际建议:大多数情况下使用受控组件,因为它更符合 React 声明式的数据流理念,且提供了最大的控制力。当表单极其简单或需要优化高频输入性能时(如富文本编辑器),可以非受控模式作为补充。

表单数据绑定与提交

React 没有 Vue 中的 v-model 双向绑定语法糖,而是通过 value(展示数据) + onChange(更新数据) 实现单向数据流。这种显式的方式让数据流向更清晰,缺点是需要在每个字段上写重复代码。

封装通用的表单绑定 Hook 减少重复

function useFormField(initialValue = '') {
  const [value, setValue] = useState(initialValue);
  const onChange = (e) => setValue(e.target.value);
  return { value, onChange };
}

// 使用
function MyForm() {
  const nameField = useFormField('');
  const emailField = useFormField('');

  return (
    <form>
      <input type="text" {...nameField} placeholder="姓名" />
      <input type="email" {...emailField} placeholder="邮箱" />
    </form>
  );
}

处理多种表单元素

  • 文本框/密码/邮件value + onChange
  • 复选框checked 属性,onChange 中读取 e.target.checked
  • 单选按钮:相同 name 属性,checked 根据当前值判断。
  • 下拉选择<select>value 属性(不同于原生 HTML 的 selected 属性)。
function FullForm() {
  const [form, setForm] = useState({
    subscribe: false,
    gender: 'male',
    city: 'beijing',
  });

  const handleChange = (e) => {
    const { name, value, type, checked } = e.target;
    setForm({
      ...form,
      [name]: type === 'checkbox' ? checked : value,
    });
  };

  return (
    <form>
      <label>
        <input
          type="checkbox"
          name="subscribe"
          checked={form.subscribe}
          onChange={handleChange}
        />
        订阅邮件
      </label>

      <div>
        <label>
          <input
            type="radio"
            name="gender"
            value="male"
            checked={form.gender === 'male'}
            onChange={handleChange}
          />
          男
        </label>
        <label>
          <input
            type="radio"
            name="gender"
            value="female"
            checked={form.gender === 'female'}
            onChange={handleChange}
          />
          女
        </label>
      </div>

      <select name="city" value={form.city} onChange={handleChange}>
        <option value="beijing">北京</option>
        <option value="shanghai">上海</option>
      </select>
    </form>
  );
}

实战注意事项

  1. 受控组件的 value 必须绑定 state:如果设置了 value 而没有提供 onChange,React 会警告,因为此时输入框变成了只读。若确实需要只读,使用 readOnly 属性。
  1. 表单提交时的默认行为onSubmit 事件中必须调用 e.preventDefault() 阻止页面刷新。
  1. 非受控组件的 defaultValue 只在挂载时生效:后续更新不会改变 DOM 值。如需动态重置表单,最好使用受控组件,或结合 key 属性强制重新挂载。
  1. 大型表单推荐使用专业库:React Hook Form(利用非受控模式,性能优异)或 Formik(声明式校验)能显著减少样板代码,并提供完善的校验和错误处理。但掌握原生控制原理是优雅使用这些库的前提。

受控组件体现了 React 声明式编程的精髓:描述状态到视图的映射,让框架保证它们的一致性。掌握后,你将能够从容应对从简单登录框到复杂多步骤表单的任何场景。