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

React多步骤表单重复提交排查及重置功能求助

问题解决与代码修改

核心问题分析

你当前的代码里,所有步骤的按钮都是type="submit",点击时都会触发表单的onSubmit事件,也就是handleSubmit函数——而这个函数里不管是不是最后一步,都执行了databases.createDocument,所以每次点Next都会提交一次数据,三次步骤就提交三次。

针对性修改方案

1. 拆分按钮类型与逻辑

把Next和Submit按钮分开处理:非最后一步的按钮用type="button",只做步骤切换;最后一步用type="submit"负责提交。修改按钮部分代码:

<div className="form-footer">
  {step !== 0 && (
    <button
      type="button"
      className="form-btn btn"
      onClick={() => handleNavigation("back")}
    >
      <FaArrowLeftLong />
    </button>
  )}
  {/* 拆分Next和Submit按钮 */}
  {step === FormHeaders.length - 1 ? (
    <button className="form-btn btn next" type="submit">
      <h2 className="next-page">
        Submit
        <i>
          <FaRegPaperPlane />
        </i>
      </h2>
    </button>
  ) : (
    <button 
      className="form-btn btn next" 
      type="button"
      onClick={() => handleNavigation("next")}
    >
      <h2 className="next-page">
        Next Page
        <i>
          <FaArrowRightLong />
        </i>
      </h2>
    </button>
  )}
</div>

2. 修正提交函数逻辑

现在只有最后一步会触发handleSubmit,所以把提交和重置逻辑放在这里:

const handleSubmit = async (e) => {
  e.preventDefault();

  try {
    // 仅在最后一步执行提交
    const response = await databases.createDocument(
      DATABASE_ID,
      COLLECTION_ID_USERS,
      ID.unique(),
      formData
    );
    console.log("Created", response);
    alert("Submission completed");
    
    // 提交成功后重置表单和步骤
    setFormData({
      stdName: "",
      stdMiddleName: "",
      stdSurname: "",
      stdGender: "",
      stdPOB: "",
      stdDOB: "",
      fatherName: "",
      motherName: "",
    });
    setStep(0);
  } catch (err) {
    console.error("提交失败", err);
    alert("提交失败,请重试");
  }
};

3. 简化导航函数

去掉handleNavigation里的submit分支,现在它只负责步骤切换:

const handleNavigation = (action) => {
  if (action === "next" && step < FormHeaders.length - 1) {
    setStep(step + 1);
  } else if (action === "back" && step > 0) {
    setStep(step - 1);
  }
};

修改后的完整代码

import React, { useState } from "react";
import {
  COLLECTION_ID_USERS,
  DATABASE_ID,
  databases,
} from "../../appwriteConfig";
import { ID } from "appwrite";
import {
  FaRegPaperPlane,
  FaArrowLeftLong,
  FaArrowRightLong,
} from "react-icons/fa6";
import { FileUpload, ParentInfo, StudentInfo } from "..";
import * as yup from "yup";

import "./multistepForm.css";

const MultistepForm = () => {
  const [step, setStep] = useState(0);
  const [formData, setFormData] = useState({
    stdName: "",
    stdMiddleName: "",
    stdSurname: "",
    stdGender: "",
    stdPOB: "",
    stdDOB: "",
    fatherName: "",
    motherName: "",
  });

  const handleNavigation = (action) => {
    if (action === "next" && step < FormHeaders.length - 1) {
      setStep(step + 1);
    } else if (action === "back" && step > 0) {
      setStep(step - 1);
    }
  };

  const handleSubmit = async (e) => {
    e.preventDefault();

    try {
      const response = await databases.createDocument(
        DATABASE_ID,
        COLLECTION_ID_USERS,
        ID.unique(),
        formData
      );
      console.log("Created", response);
      alert("Submission completed");
      
      // 重置表单数据和步骤
      setFormData({
        stdName: "",
        stdMiddleName: "",
        stdSurname: "",
        stdGender: "",
        stdPOB: "",
        stdDOB: "",
        fatherName: "",
        motherName: "",
      });
      setStep(0);
    } catch (err) {
      console.error("提交失败", err);
      alert("提交失败,请重试");
    }
  };

  const FormHeaders = [
    "Student Information",
    "Parent Information",
    "Upload Files",
  ];

  const StepDisplay = () => {
    switch (step) {
      case 0:
        return <StudentInfo formData={formData} setFormData={setFormData} />;
      case 1:
        return <ParentInfo formData={formData} setFormData={setFormData} />;
      default:
        return <FileUpload formData={formData} setFormData={setFormData} />;
    }
  };

  return (
    <div className="form">
      <h2 className="form-title">Online Application</h2>
      <div className="progressbar">
        <div
          style={{
            width: step === 0 ? "33.3%" : step === 1 ? "66.6%" : "100%",
          }}
        ></div>
      </div>
      <div className="form-container">
        <h1 className="form-header">{FormHeaders[step]}</h1>
        <div className="form-body">
          <form onSubmit={handleSubmit} action="#">
            {StepDisplay()}
            <div className="form-footer">
              {step !== 0 && (
                <button
                  type="button"
                  className="form-btn btn"
                  onClick={() => handleNavigation("back")}
                >
                  <FaArrowLeftLong />
                </button>
              )}
              {step === FormHeaders.length - 1 ? (
                <button className="form-btn btn next" type="submit">
                  <h2 className="next-page">
                    Submit
                    <i>
                      <FaRegPaperPlane />
                    </i>
                  </h2>
                </button>
              ) : (
                <button 
                  className="form-btn btn next" 
                  type="button"
                  onClick={() => handleNavigation("next")}
                >
                  <h2 className="next-page">
                    Next Page
                    <i>
                      <FaArrowRightLong />
                    </i>
                  </h2>
                </button>
              )}
            </div>
          </form>
        </div>
      </div>
    </div>
  );
};

export default MultistepForm;

关键说明

  • 非最后一步的按钮用type="button",避免触发表单提交,只执行步骤切换。
  • 仅在最后一步点击Submit时,才会调用Appwrite的创建文档接口,解决了多次提交的问题。
  • 提交成功后,通过setFormData重置表单数据,setStep(0)回到初始步骤,完成表单重置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 15:54:54