如何在使用 Formik 提交后保留表单值

How to retain form values after submission with Formik

我是第一次使用 React。我已经用 Formik 连接了一个表单,并且所有的验证工作都在工作,但如果出现问题,我会坚持保留表单值。

表单收集数据以将记录添加到数据库中。如果 API 响应有数据,则插入成功并且我显示成功警报。如果插入失败,则数据为空,因为从 API 返回了 null 并且我显示了危险警报。

我的问题是,如果出现错误,我该如何保留表单字段的值?我想关闭危险警报并仍然填充表单字段,这样用户就不必重新开始。我不需要在成功时执行此操作,因为用户输入的信息已进入数据库。

我觉得这与表单本身或字段的状态有关,但我不知道如何保留这些值。我尝试在 onSubmit 中执行 ...values 但这没有用(不太了解传播的东西)。任何帮助将不胜感激。

这是我的:

import React, { useState } from "react"
import * as Yup from "yup"
import { Formik, Form, Field } from "formik"
import "../../custom.css"
import * as apiService from "./../../services/apiService"
import DatePicker from "../../utils/DatePicker"
import "react-datepicker/dist/react-datepicker.css"
import Alert from "reactstrap/lib/Alert"
import { Button } from "reactstrap"
import "bootstrap/dist/css/bootstrap.min.css"

const CompanyMasterAdd = () => {
  const [showAlert, setShowAlert] = useState(false)
  const [apiResponse, setApiResponse] = useState(null)
  const urlRegex =
    /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)/

  //Setup values for drop downs so we can validate against selection
  //This one is set here because we need to access statuses in the YUP validation
  const statuses = ["1", "2", "3", "4", "5"]
  const statusOptions = statuses.map((statusID, key) => (
    <option value={statusID} key={key}>
      {statusID}
    </option>
  ))

  //setup validation requirements and error messages for fields via Yup
  const companyMasterAddSchema = Yup.object().shape({
    companyId: Yup.number()
      //custom required message when required field not filled in
      .required("Company Id is required")
      //if it's not a number, display custom error message
      .typeError("Company Id must be a number")
      .positive()
      .integer(),
    companyName: Yup.string()
      .max(75, "Must be 75 characters or less")
      .required("Company Name is required"),
    databaseName: Yup.string()
      .required("Database Name is required")
      .max(100, "Must be 100 characters or less"),
    statusID: Yup.string().required("Status ID is required").oneOf(statuses),
    website: Yup.string().matches(urlRegex, "Website URL is not valid"),
  })

  //Setup values for drop downs so we can validate against selection
  const companyTypes = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]

  const companyTypeOptions = companyTypes.map((companyTypeID, key) => (
    <option value={companyTypeID} key={key}>
      {companyTypeID}
    </option>
  ))

  //dismiss alert when button is closed
  const onDismiss = () => {
    setShowAlert(false)
  }
  return (
    <div id="companyMasterPageContainer">
      <h1>Add Company Master record</h1>
      <hr />
      {showAlert ? (
        <div>
          <Alert
            color={apiResponse && !apiResponse.data ? "danger" : "success"}
          >
            <h4 className="alert-heading">
              {apiResponse && !apiResponse.data ? "ERROR" : "SUCCESS"}
            </h4>
            <p>
              {apiResponse && !apiResponse.data
                ? 
                //TODO: keep form data populated if there is a failure
                //TODO: get the actual error from the API somehow
                "An error occurred. Check the ProcedureErrorLog table"
                : "Record added"}
            </p>
            <hr />
            <Button onClick={() => onDismiss()}>Dismiss</Button>
          </Alert>
        </div>
      ) : (
        // show form if showAlert is false
        <div id="companyMasterAddFormContainer">
          <h2>Form area</h2>
          <Formik
            initialValues={{
              companyId: "",
              companyName: "",
              website: "",
              fiscalYearEnd: null,
              taxIDNumber: "",
              companyTypeID: "",
              isKeyCompany: false,
              databaseName: "",
              statusID: "",
            }}
            validationSchema={companyMasterAddSchema}
            onSubmit={async (
              values,
              { resetForm, setSubmitting, isSubmitting }
            ) => {
              apiService.addCompanyMaster(values).then((response) => {
                setApiResponse(response)
                setShowAlert(true)
              })
            }}
          >
            {({ errors, touched, values, setFieldValue }) => (
              <Form id="companyMasterAddForm">
                <div>
                  <span className="requiredStar">
                    * indicates a required field
                  </span>
                </div>
                <div className="row">
                  <div className="formLabel">
                    <label
                      htmlFor="companyId"
                      className="companyMasterAddFormLabel"
                    >
                      Company ID <span className="requiredStar">*</span>
                    </label>
                  </div>
                  <div className="formInput">
                    <Field
                      value={values.companyId}
                      type="text"
                      id="companyId"
                      className="companyMasterAddFormField"
                      name="companyId"
                      placeholder="e.g., 1,2,3..."
                    />
                    {/* If this field has been touched, and it contains an error, display it  */}
                    {touched.companyId && errors.companyId && (
                      <div className="formError">{errors.companyId}</div>
                    )}
                  </div>
                </div>
                <div className="row">
                  <div className="formLabel">
                    <label
                      className="companyMasterAddFormLabel"
                      htmlFor="fiscalYearEnd"
                    >
                      Fiscal Year End
                    </label>
                  </div>
                  <div className="formInput">
                    <DatePicker
                      name="fiscalYearEnd"
                      value={values.fiscalYearEnd}
                      onChange={setFieldValue}
                      className="companyMasterAddFormField"
                      class="companyMasterAddFormField"
                    />
                    {/* If this field has been touched, and it contains an error, display it  */}
                    {touched.fiscalYearEnd && errors.fiscalYearEnd && (
                      <div className="formError">{errors.fiscalYearEnd}</div>
                    )}
                  </div>
                </div>
                <div className="row">
                  <button
                    type="submit"
                    style={{
                      textAlign: "center",
                      marginLeft: "30%",
                      marginRight: "30%",
                    }}
                  >
                    Submit
                  </button>
                </div>
              </Form>
            )}
          </Formik>
        </div>
      )}
    </div>
  )
}

export default CompanyMasterAdd

更新 - 可以使用了
分离警报的条件逻辑和表单:

{
        showAlert && (
          <div>
            <Alert
              color={apiResponse && !apiResponse.data ? "danger" : "success"}
            >
              <h4 className="alert-heading">
                {apiResponse && !apiResponse.data ? "ERROR" : "SUCCESS"}
              </h4>
              <p>
                {apiResponse && !apiResponse.data
                  ? //TODO: keep form data populated if there is a failure
                    "An error occurred. Check the xyztable in the database"
                  : "Record added"}
              </p>
              <hr />
              <Button onClick={() => onDismiss()}>Dismiss</Button>
            </Alert>
          </div>
        )
        // show form if showAlert is false
      }
      <div
        id="companyMasterAddFormContainer"
        style={{ visibility: open ? "visible" : "hidden" }}
      >
        <h2>Form area</h2>

        <Formik
          initialValues={{

奖金 - 显示警报时隐藏表格

  1. 添加了新的状态变量:
const [open, setOpen] = useState(true)
  1. 在 div 容器中为表单添加了可见性样式:
<div
        id="companyMasterAddFormContainer"
        style={{ visibility: open ? "visible" : "hidden" }}
      >
  1. 在表单的onSubmit区域切换打开状态:
onSubmit={async (
            values,
            { resetForm, setSubmitting, isSubmitting }
          ) => {
            setSubmitting(false)
            apiService.addCompanyMaster(values).then((response) => {
              setApiResponse(response)
              setShowAlert(true)
              setOpen(false)
              if (response && response.data) {
                resetForm()
              }
            })
  1. 切换警报解除状态:
const onDismiss = () => {
    setShowAlert(false)
    setOpen(true)
  }

Formik 组件是表单状态所在的位置(例如 valuestouchederrors)。您正在条件中渲染 Formik。每次提交表单时,您都将 showAlert 设置为 true,这会从 DOM 中删除 Formik 组件及其子组件。相反,您应该有条件地呈现警报,同时始终呈现 Formik 组件。

然后在onSubmit函数里面,插入成功后可以调用resetForm回调