You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React.js如何实现点击提交按钮触发表单校验通过后再提交

问题描述

我有一个基础React表单,包含email、confirmEmail两个输入框,功能为更新用户邮箱地址,同时校验两次输入的新邮箱地址是否一致。

  • 现有校验逻辑可正常运行:当email与confirmEmail输入值不匹配、或任一输入框为空时,会抛出对应错误提示。
  • 需调整校验触发时机:
    • 将所有校验逻辑迁移至submit按钮的点击事件中,仅当点击提交按钮时才执行校验、高亮显示错误信息
    • 仅当所有输入值校验合法时,才更新registeredEmail状态完成提交

现有代码片段如下:

import React, { useState } from "react";

function Form() {
  const [registeredEmail, setRegisteredEmail] = useState("JohnDoe@gmail.com");

  const [input, setInput] = useState({
    email: "",
    confirmEmail: ""
  });

  const [error, setError] = useState({
    email: "",
    confirmEmail: ""
  });

  const onInputChange = (e) => {
    const { name, value } = e.target;
    setInput((prev) => ({
      ...prev,
      [name]: value
    }));
    validateInput(e);
  };

  const validateInput = (e) => {
    let { name, value } = e.target;
    setError((prev) => {
      const stateObj = { ...prev, [name]: "" };

      switch (name) {
        case "email":
          if (!value) {
            stateObj[name] = "Please enter Email";
          } else if (input.confirmEmail && value !== input.confirmEmail) {
            stateObj["confirmEmail"] =
              "Email and Confirm Email does not match.";
          } else {
            stateObj["confirmEmail"] = input.confirmEmail
              ? ""
              : error.confirmEmail;
          }
          break;

        case "confirmEmail":
          if (!value) {
            stateObj[name] = "Please enter Confirm Email.";
          } else if (input.email && value !== input.email) {
            stateObj[name] = "Email and Confirm Email does not match.";
          }
          break;

        default:
          break;
      }

      return stateObj;
    });
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    validateInput(e);
    setRegisteredEmail(input.email);
  };

  return (
    <>
      <header>{registeredEmail}</header>
      <form
        style={{
          display: "flex",
          flexDirection: "column"
        }}
      >
        <input
          type="email"
          name="email"
          placeholder="address"
          onChange={onInputChange}
          value={input.email}
        />
        {error.email && <span style={{ color: "red" }}>{error.email}</span>}

        <input
          onChange={onInputChange}
          value={input.confirmEmail}
          type="email"
          name="confirmEmail"
          placeholder="repeat address"
        />
        {error.confirmEmail && (
          <span style={{ color: "red" }}>{error.confirmEmail}</span>
        )}
      </form>
      <button onClick={handleSubmit}>speichern</button>
    </>
  );
}

export default Form;
解决方案

核心修改点共3处:

  • 移除输入框onChange事件中绑定的实时校验逻辑,输入过程中仅同步更新表单值,不触发任何校验、不展示错误提示
  • 重构校验逻辑为全量校验函数,不再依赖单个输入框的事件对象,提交时一次性校验两个字段的合法性,同步生成所有错误信息,返回布尔值标识表单是否通过校验
  • 调整提交逻辑:点击提交按钮后先执行全量校验,仅当所有字段校验通过时才更新registeredEmail状态完成提交,校验不通过时直接渲染对应错误提示

修改后完整可运行代码:

import React, { useState } from "react";

function Form() {
  const [registeredEmail, setRegisteredEmail] = useState("JohnDoe@gmail.com");

  const [input, setInput] = useState({
    email: "",
    confirmEmail: ""
  });

  const [error, setError] = useState({
    email: "",
    confirmEmail: ""
  });

  // 输入时仅更新表单值,不触发校验
  const onInputChange = (e) => {
    const { name, value } = e.target;
    setInput((prev) => ({
      ...prev,
      [name]: value
    }));
  };

  // 提交时全量校验所有字段,返回校验结果
  const validateAllFields = () => {
    const newError = {
      email: "",
      confirmEmail: ""
    };
    let isValid = true;

    if (!input.email.trim()) {
      newError.email = "Please enter Email";
      isValid = false;
    }

    if (!input.confirmEmail.trim()) {
      newError.confirmEmail = "Please enter Confirm Email.";
      isValid = false;
    } else if (input.email.trim() && input.email !== input.confirmEmail) {
      newError.confirmEmail = "Email and Confirm Email does not match.";
      isValid = false;
    }

    setError(newError);
    return isValid;
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    const isFormValid = validateAllFields();
    // 仅校验通过时更新已注册邮箱
    if (isFormValid) {
      setRegisteredEmail(input.email);
      // 提交成功后可按需清空输入框
      setInput({ email: "", confirmEmail: "" });
    }
  };

  return (
    <>
      <header>{registeredEmail}</header>
      <form
        style={{
          display: "flex",
          flexDirection: "column"
        }}
        onSubmit={handleSubmit}
      >
        <input
          type="email"
          name="email"
          placeholder="address"
          onChange={onInputChange}
          value={input.email}
        />
        {error.email && <span style={{ color: "red" }}>{error.email}</span>}

        <input
          onChange={onInputChange}
          value={input.confirmEmail}
          type="email"
          name="confirmEmail"
          placeholder="repeat address"
        />
        {error.confirmEmail && (
          <span style={{ color: "red" }}>{error.confirmEmail}</span>
        )}
        <button type="submit">speichern</button>
      </form>
    </>
  );
}

export default Form;

额外优化说明:将提交事件绑定到<form>标签的onSubmit属性、按钮设置type="submit",可以原生支持输入框聚焦时按回车触发表单提交,符合常规表单交互习惯。


内容的提问来源于stack exchange,提问作者FD3

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 22:21:46