Skip to content

表单组件

在 React 中处理表单是一个常见的任务,React 提供了多种方式来管理表单数据和用户输入。你可以使用受控组件(Controlled Components)、非受控组件(Uncontrolled Components)或结合 Hooks 和自定义逻辑来创建功能丰富且易于维护的表单。

受控组件(Controlled Components)

在受控组件中,表单元素的值由 React 的状态管理,并通过 value 属性传递给这些元素。每当用户输入内容时,都会触发一个事件处理器来更新状态,从而保持同步。这种方式使得你可以完全控制表单的状态和行为。

示例:文本输入框

jsx
import React, { useState } from "react";

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

  function handleChange(event) {
    setName(event.target.value);
  }

  function handleSubmit(event) {
    alert("A name was submitted: " + name);
    event.preventDefault();
  }

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Name:
        <input type="text" value={name} onChange={handleChange} />
      </label>
      <input type="submit" value="Submit" />
    </form>
  );
}

在这个例子中,NameForm 组件使用 useState 来跟踪输入框的值,并通过 onChange 事件处理器更新这个状态。当用户提交表单时,会弹出一个警告框显示输入的名字。

处理多个输入

对于包含多个输入字段的表单,你可以将每个字段的状态存储在一个对象中,并根据 name 属性来区分不同的输入:

jsx
import React, { useState } from "react";

function FormWithMultipleInputs() {
  const [formData, setFormData] = useState({
    username: "",
    email: "",
  });

  function handleChange(event) {
    const { name, value } = event.target;
    setFormData((prevState) => ({
      ...prevState,
      [name]: value,
    }));
  }

  function handleSubmit(event) {
    alert(`Username: ${formData.username}, Email: ${formData.email}`);
    event.preventDefault();
  }

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label>
          Username:
          <input
            name="username"
            type="text"
            value={formData.username}
            onChange={handleChange}
          />
        </label>
      </div>
      <div>
        <label>
          Email:
          <input
            name="email"
            type="email"
            value={formData.email}
            onChange={handleChange}
          />
        </label>
      </div>
      <button type="submit">Submit</button>
    </form>
  );
}

非受控组件(Uncontrolled Components)

与受控组件不同,在非受控组件中,表单元素的值不由 React 管理,而是直接保存在 DOM 中。你可以使用 ref 来获取这些元素的当前值。这种方式更接近传统的 HTML 表单处理方式,但在某些情况下可能会更加简洁。

示例:使用 useRef

jsx
import React, { useRef } from "react";

function UncontrolledForm() {
  const inputEl = useRef(null);

  function handleSubmit(event) {
    alert("A name was submitted: " + inputEl.current.value);
    event.preventDefault();
  }

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label>
          Name:
          <input ref={inputEl} type="text" />
        </label>
      </div>
      <button type="submit">Submit</button>
    </form>
  );
}

在这个例子中,我们使用 useRef 创建了一个引用对象 inputEl,并将其赋值给 <input> 元素的 ref 属性。然后在提交表单时,可以通过 inputEl.current.value 获取输入框的值。

文件上传

处理文件上传时,你可以使用 <input type="file" /> 元素,并结合受控或非受控的方式读取文件信息。

示例:受控文件上传

jsx
import React, { useState } from "react";

function FileUpload() {
  const [selectedFile, setSelectedFile] = useState(null);

  function handleFileChange(event) {
    setSelectedFile(event.target.files[0]);
  }

  function handleSubmit(event) {
    if (selectedFile) {
      console.log(selectedFile);
    }
    event.preventDefault();
  }

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label>
          Upload file:
          <input type="file" onChange={handleFileChange} />
        </label>
      </div>
      <button type="submit">Submit</button>
    </form>
  );
}

表单验证

React 不提供内置的表单验证机制,但你可以很容易地实现自己的验证逻辑。通常的做法是在提交表单前检查各个字段的有效性,并根据需要显示错误消息。

示例:简单验证

jsx
import React, { useState } from "react";

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

  function validateEmail(email) {
    // 简单的正则表达式验证
    const re = /\S+@\S+\.\S+/;
    return re.test(String(email).toLowerCase());
  }

  function handleChange(event) {
    setEmail(event.target.value);
  }

  function handleSubmit(event) {
    if (!validateEmail(email)) {
      setError("Invalid email address");
    } else {
      setError("");
      alert("Valid email address!");
    }
    event.preventDefault();
  }

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label>
          Email:
          <input type="email" value={email} onChange={handleChange} />
        </label>
      </div>
      {error && <p style={{ color: "red" }}>{error}</p>}
      <button type="submit">Submit</button>
    </form>
  );
}

在这个例子中,我们在提交表单时调用 validateEmail 函数来检查电子邮件地址是否有效。如果无效,则显示一条错误消息;否则,显示成功提示。

使用 Hook 和自定义逻辑

随着 React 的发展,越来越多的功能可以通过 Hooks 实现。例如,你可以创建自定义 Hook 来封装表单逻辑,或者使用第三方库如 Formikreact-hook-form 来简化复杂的表单处理。

示例:使用 react-hook-form

react-hook-form 是一个流行的库,它提供了非常轻量级的 API 来处理表单,同时支持验证、异步验证等功能。

首先安装库:

bash
npm install react-hook-form

然后使用它来构建表单:

jsx
import React from "react";
import { useForm } from "react-hook-form";

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

  function onSubmit(data) {
    console.log(data);
  }

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div>
        <label>First Name</label>
        <input {...register("firstName", { required: true })} />
        {errors.firstName && <p>First Name is required</p>}
      </div>
      <div>
        <label>Last Name</label>
        <input {...register("lastName")} />
      </div>
      <input type="submit" />
    </form>
  );
}

export default HookFormExample;

在这个例子中,我们使用了 react-hook-form 提供的 useForm Hook 来注册表单字段,并在提交时获取它们的值。此外,还可以轻松地添加验证规则并在必要时显示错误消息。

总结

React 提供了灵活的方式来处理表单,无论是通过受控组件还是非受控组件,或者是结合 Hooks 和第三方库。选择哪种方式取决于你的具体需求和个人偏好。无论采用何种方法,都应该确保代码清晰易懂,并且能够有效地管理和验证用户输入。

Released under the MIT License.