如何在使用 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={{
奖金 - 显示警报时隐藏表格
- 添加了新的状态变量:
const [open, setOpen] = useState(true)
- 在 div 容器中为表单添加了可见性样式:
<div
id="companyMasterAddFormContainer"
style={{ visibility: open ? "visible" : "hidden" }}
>
- 在表单的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()
}
})
- 切换警报解除状态:
const onDismiss = () => {
setShowAlert(false)
setOpen(true)
}
Formik
组件是表单状态所在的位置(例如 values
、touched
、errors
)。您正在条件中渲染 Formik
。每次提交表单时,您都将 showAlert
设置为 true
,这会从 DOM 中删除 Formik
组件及其子组件。相反,您应该有条件地呈现警报,同时始终呈现 Formik
组件。
然后在onSubmit
函数里面,插入成功后可以调用resetForm
回调
我是第一次使用 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={{
奖金 - 显示警报时隐藏表格
- 添加了新的状态变量:
const [open, setOpen] = useState(true)
- 在 div 容器中为表单添加了可见性样式:
<div
id="companyMasterAddFormContainer"
style={{ visibility: open ? "visible" : "hidden" }}
>
- 在表单的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()
}
})
- 切换警报解除状态:
const onDismiss = () => {
setShowAlert(false)
setOpen(true)
}
Formik
组件是表单状态所在的位置(例如 values
、touched
、errors
)。您正在条件中渲染 Formik
。每次提交表单时,您都将 showAlert
设置为 true
,这会从 DOM 中删除 Formik
组件及其子组件。相反,您应该有条件地呈现警报,同时始终呈现 Formik
组件。
然后在onSubmit
函数里面,插入成功后可以调用resetForm
回调