面试题:React 处理表单输入的方法有哪些?

在 React 中处理表单输入是常见且重要的任务。由于 React 的“单向数据流”和“状态驱动视图”特性,表单处理与原生 JavaScript 有所不同。主要方法分为两大类:受控组件 (Controlled Components)非受控组件 (Uncontrolled Components)


一、受控组件 (Controlled Components) – 推荐方式

这是 React 中处理表单的标准和推荐做法。表单元素的值由 React 组件的 state 控制,用户输入通过事件处理器实时更新 statestate 的变化又驱动视图更新。

核心思想

  • 数据源单一:表单的值(value)由 React 的 state 决定。
  • 双向绑定:通过 onChange 事件监听用户输入,并立即更新 state

基本示例

import React, { useState } from 'react';

function NameForm() {
  const [name, setName] = useState('');

  const handleChange = (e) => {
    setName(e.target.value);
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    alert('提交的名字: ' + name);
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        名字:
        <input
          type="text"
          value={name}           // 值由 state 控制
          onChange={handleChange} // 输入时更新 state
        />
      </label>
      <button type="submit">提交</button>
    </form>
  );
}

处理多种输入类型

可以使用一个通用的 handleChange 函数处理多个输入字段。

function UserForm() {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    isSubscribed: false
  });

  const handleChange = (e) => {
    const { name, value, type, checked } = e.target;
    // 对于复选框,使用 checked 属性
    setFormData(prev => ({
      ...prev,
      [name]: type === 'checkbox' ? checked : value
    }));
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log(formData);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        name="name"
        value={formData.name}
        onChange={handleChange}
        placeholder="姓名"
      />
      <input
        name="email"
        value={formData.email}
        onChange={handleChange}
        placeholder="邮箱"
      />
      <label>
        <input
          name="isSubscribed"
          type="checkbox"
          checked={formData.isSubscribed}
          onChange={handleChange}
        />
        订阅邮件
      </label>
      <button type="submit">提交</button>
    </form>
  );
}

优点

  • 数据一致性:React state 是唯一数据源,易于管理和调试。
  • 实时验证:可以在 onChange 中立即进行输入验证。
  • 灵活控制:可以轻松格式化输入、限制字符等。
  • 符合 React 思想:声明式 UI,状态驱动。

缺点

  • 样板代码较多:每个输入都需要 stateonChange 处理器。
  • 性能:对于大量输入,频繁的 setState 可能有轻微性能开销(通常可忽略)。

二、非受控组件 (Uncontrolled Components)

非受控组件将表单数据的管理交给 DOM 本身,而不是 React 的 state。使用 ref 来直接访问 DOM 元素,获取其值。

核心思想

  • 数据源在 DOM:表单元素自己管理自己的值。
  • 通过 ref 获取值:在需要时(如提交时)通过 ref 读取 DOM 的当前值。

基本示例

import React, { useRef } from 'react';

function NameForm() {
  const inputRef = useRef();

  const handleSubmit = (e) => {
    e.preventDefault();
    // 通过 ref 访问 DOM 元素的值
    alert('名字: ' + inputRef.current.value);
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        名字:
        <input type="text" ref={inputRef} />
      </label>
      <button type="submit">提交</button>
    </form>
  );
}

设置默认值

使用 defaultValuedefaultChecked 属性。

<input
  defaultValue="初始值"
  ref={inputRef}
/>

优点

  • 简单直接:对于简单表单或不需要实时控制的场景,代码更少。
  • 集成非 React 代码:方便与需要直接操作 DOM 的第三方库(如 jQuery 插件)集成。
  • 性能:避免了频繁的 setState 调用。

缺点

  • 数据分散:表单数据不在 React state 中,难以进行集中管理和调试。
  • 无法实时验证:不能在输入过程中实时响应和验证。
  • 灵活性差:难以动态控制输入值(如格式化、限制)。
  • 不符合 React 理念:更像是原生 JavaScript 的做法。

三、使用第三方库

对于复杂的表单(如嵌套结构、复杂验证、动态字段),手动管理状态会变得繁琐。可以使用成熟的表单库:

  1. React Hook Form
    • 理念:推崇非受控组件,性能极高。
    • 特点:体积小、性能好、支持 Yup 等验证库、类型安全。
    • 适合:大多数场景,尤其是性能敏感的大型表单。
  2. Formik
    • 理念:基于受控组件。
    • 特点:功能全面,API 友好,社区成熟。
    • 适合:需要复杂逻辑和验证的表单。

React Hook Form 示例

import { useForm } from 'react-hook-form';

function MyForm() {
  const { register, handleSubmit, formState: { errors } } = useForm();

  const onSubmit = (data) => {
    console.log(data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register("name", { required: true })} />
      {errors.name && <span>名字是必填的</span>}
      
      <input type="submit" />
    </form>
  );
}

四、总结与选择

方法适用场景推荐度
受控组件需要实时验证、动态控制、数据集中管理的表单。现代 React 的标准做法✅✅✅ 强烈推荐
非受控组件简单表单、需要与非 React 库集成、性能要求极高且无需实时控制的场景。⚠️ 特定场景使用
第三方库 (如 React Hook Form)复杂表单、需要强大验证、减少样板代码的项目。✅✅ 大型/复杂项目推荐

结论: 对于大多数 React 应用,受控组件是首选方法。它与 React 的设计理念完美契合,提供了更好的控制力和可维护性。当表单变得复杂时,应考虑使用 React Hook Form 这样的库来简化开发。非受控组件仅在特定需求下作为补充。

THE END
喜欢就支持一下吧
点赞11 分享