Skip to content

受控组件

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

受控组件的基本概念

  • 状态(State):使用 useState 或其他状态管理机制来保存表单字段的值。
  • 事件处理器(Event Handlers):监听用户的输入事件(如 onChange),并在事件发生时更新状态。
  • 同步(Synchronization):通过将状态绑定到表单元素的 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>
  );
}

export default NameForm;

在这个例子中,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>
  );
}

export default FormWithMultipleInputs;

受控选择框(Select Box)

处理 <select> 元素与处理文本输入类似,但需要注意的是你需要为每个选项设置 value 属性,并且在状态中保存所选选项的值。

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

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

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

  function handleSubmit(event) {
    alert("Your favorite flavor is: " + flavor);
    event.preventDefault();
  }

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Pick your favorite La Croix flavor:
        <select value={flavor} onChange={handleChange}>
          <option value="grapefruit">Grapefruit</option>
          <option value="lime">Lime</option>
          <option value="coconut">Coconut</option>
          <option value="mango">Mango</option>
        </select>
      </label>
      <input type="submit" value="Submit" />
    </form>
  );
}

export default FlavorForm;

受控复选框(Checkbox)

处理复选框稍微有些不同,因为它们有 checked 而不是 value 属性。你需要用布尔值来表示是否选中。

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

function ToggleButton() {
  const [isToggled, setIsToggled] = useState(false);

  function handleChange(event) {
    setIsToggled(event.target.checked);
  }

  return (
    <label>
      Toggle me
      <input type="checkbox" checked={isToggled} onChange={handleChange} />
    </label>
  );
}

export default ToggleButton;

文件上传

处理文件上传时,你可以使用 <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>
  );
}

export default FileUpload;

表单验证

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>
  );
}

export default ValidatedForm;

使用 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 中一种强大且灵活的方式来管理表单数据和用户输入。通过将表单元素的状态与 React 的状态同步,你可以获得对表单的全面控制,包括实时验证、格式化和响应用户交互。

Released under the MIT License.