【发布时间】:2021-09-09 17:04:15
【问题描述】:
我是第一次使用 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)
}
【问题讨论】:
标签: reactjs react-hooks react-router formik