返回教程列表
教程 React 快速入门 第 6 节
进阶
20 分钟

表单处理

学习在 React 中处理表单,掌握受控组件和非受控组件

CodeGogo

受控组件

表单元素(如 <input><textarea><select>)的值由 React 控制,称为受控组件。

基本示例

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

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

  return (
    <form onSubmit={handleSubmit}>
      <label>
        名字:
        <input
          type="text"
          value={name}
          onChange={(e) => setName(e.target.value)}
        />
      </label>
      <button type="submit">提交</button>
    </form>
  );
}

textarea 标签

function EssayForm() {
  const [value, setValue] = useState('请在此撰写文章...');

  return (
    <form>
      <label>
        文章:
        <textarea
          value={value}
          onChange={(e) => setValue(e.target.value)}
          rows={5}
          cols={30}
        />
      </label>
    </form>
  );
}

select 标签

function FlavorForm() {
  const [flavor, setFlavor] = useState('coconut');

  return (
    <form>
      <label>
        选择你喜欢的口味:
        <select value={flavor} onChange={(e) => setFlavor(e.target.value)}>
          <option value="grapefruit">葡萄柚</option>
          <option value="lime">酸橙</option>
          <option value="coconut">椰子</option>
          <option value="mango">芒果</option>
        </select>
      </label>
    </form>
  );
}

多个受控输入

function Reservation() {
  const [formData, setFormData] = useState({
    isGoing: true,
    numberOfGuests: 2
  });

  const handleChange = (event) => {
    const { name, value, type, checked } = event.target;
    setFormData(prev => ({
      ...prev,
      [name]: type === 'checkbox' ? checked : value
    }));
  };

  return (
    <form>
      <label>
        <input
          name="isGoing"
          type="checkbox"
          checked={formData.isGoing}
          onChange={handleChange}
        />
        是否参加
      </label>
      <br />
      <label>
        来宾人数:
        <input
          name="numberOfGuests"
          type="number"
          value={formData.numberOfGuests}
          onChange={handleChange}
        />
      </label>
    </form>
  );
}

非受控组件

使用 ref 从 DOM 获取表单数据。

import { useRef } from 'react';

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

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log('名字:', nameRef.current.value);
    console.log('邮箱:', emailRef.current.value);
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        名字:
        <input
          ref={nameRef}
          type="text"
          defaultValue="张三"
        />
      </label>
      <label>
        邮箱:
        <input
          ref={emailRef}
          type="email"
          defaultValue="zhangsan@example.com"
        />
      </label>
      <button type="submit">提交</button>
    </form>
  );
}

文件上传

function FileInput() {
  const fileInputRef = useRef(null);

  const handleSubmit = (e) => {
    e.preventDefault();
    const files = fileInputRef.current.files;
    console.log('选择的文件:', files);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        ref={fileInputRef}
        type="file"
        multiple
      />
      <button type="submit">上传</button>
    </form>
  );
}

表单验证

实时验证

function ValidatedForm() {
  const [email, setEmail] = useState('');
  const [error, setError] = useState('');

  const validateEmail = (email) => {
    const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return re.test(email);
  };

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

    if (value && !validateEmail(value)) {
      setError('请输入有效的邮箱地址');
    } else {
      setError('');
    }
  };

  return (
    <form>
      <label>
        邮箱:
        <input
          type="email"
          value={email}
          onChange={handleChange}
        />
        {error && <p className="error">{error}</p>}
      </label>
      <button type="submit" disabled={!!error}>
        提交
      </button>
    </form>
  );
}

💡 最佳实践

  1. 优先使用受控组件:更好的控制和验证
  2. 使用 name 属性:简化表单处理逻辑
  3. 及时验证:提供即时反馈
  4. 处理文件上传:使用 FormData API

🎯 练习

  1. 创建一个完整的注册表单
  2. 实现搜索框组件
  3. 创建一个多步骤表单(wizard form)

下一节我们将学习 组件优化技巧

觉得这个教程有帮助?

继续学习更多教程,掌握编程技能

查看更多教程