当尝试在没有 YUP 的情况下进行表单验证时,我的表单会在组件安装时继续重新运行验证。我尝试更改代码 onValidationChange 和 validationOnBlur 更改,但在运行表单验证时似乎没有任何区别。有没有办法做到这一点?
目标是在 Blur 上为必填字段和 onSubmit 显示 toast 错误消息。任何帮助都会很棒!
import React, {useState, useEffect} from 'react';
import {useToast, useBreadcrumbs} from 'hooks';
import {PipelineState, IdState, selectedCustomer} from 'states';
import {useRecoilValue, useRecoilState} from 'recoil';
import {useHistory} from 'react-router-dom';
import {Formik, Form} from 'formik';
import {Pipelines} from 'api';
import {Input, DropDownInput, DateInput, ConfirmationDialog, FormattedInput, Scheduler,
RadioButtonGroup} from 'components/Form';
import Toast from 'components/Toast';
import {FileList} from 'pages/FileGroups';
import {Contacts as CustomerIcon} from '@uitk/react-icons';
import {Button} from 'components/Styled';
import {Card} from '@uitk/react';
import {formatShortName} from 'utils';
const PipelineDetail = () => {
const history = useHistory();
const {toast, open, makeToast, eatToast} = useToast();
const [{customerId, pipelineId}, setIds] = useRecoilState(IdState);
const [{pipelineEnums, selectedPipeline}, setPipelineState] = useRecoilState(PipelineState);
const currentCustomer = useRecoilValue(selectedCustomer);
const isUpdate = pipelineId !== 'new';
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
const breadcrumbs = useBreadcrumbs();
useEffect(() => {
breadcrumbs.push(`/customers/${currentCustomer._id}`, currentCustomer.name);
}, [breadcrumbs, currentCustomer]);
const displayToastError = async msg => {
throw new Error(msg);
};
const validateForm = values => {
const errors = {};
const {name, lob} = values;
if (!name && !lob) {
errors.name = 'Pipeline name is required';
makeToast(displayToastError(errors.name));
} else if (!name && lob) {
errors.name = 'Pipeline name is required';
makeToast(displayToastError(errors.name));
} else if (name && !lob) {
errors.lob = 'Lob is required';
makeToast(displayToastError(errors.lob));
}
return errors;
};
const handleSubmit = async values => {
const data = await makeToast(
isUpdate ?
Pipelines.update(customerId, values) :
Pipelines.create(customerId, values),
`Successfully ${isUpdate ? 'updated' : 'created'} pipeline ${values.name}`
);
setPipelineState();
if (!isUpdate && !data.message) {
setIds({customerId, pipelineId: data._id});
history.push(`/customers/${customerId}/pipelines/${data._id}`);
}
};
return (
<>
<Toast
open={open}
autoHideDuration={6000}
severity={toast.severity}
message={toast.message}
onClose={eatToast}
/>
<h1>
<CustomerIcon size="l"/> {isUpdate ? selectedPipeline.name : 'New Pipeline'}
</h1>
<Formik
enableReinitialize
initialValues={selectedPipeline}
validateOnBlur={false}
validateOnChange={false}
validate={validateForm}
onSubmit={handleSubmit}
>
{({setFieldValue, setValues, values}) => (
<Card>
<Form>
<div className="grid" justify="space-between">
{!isUpdate &&
<FormattedInput
name="name"
label="Pipeline Name"
onChangeFormatter={event => {
const formattedInput = formatShortName(event.target.value);
setFieldValue('name', formattedInput);
}}
/>}
{isUpdate ?
<Input
readOnly
name="lob"
label="LOB"
/> :
<DropDownInput
items={pipelineEnums.lob}
readOnly={isUpdate}
name="lob"
label="LOB"
/>}
<RadioButtonGroup
items={pipelineEnums.runType}
name="runType"
label="Run Pipeline"
readOnly={isUpdate}
selectedType={selectedPipeline.runType}
labelKey={{immediate: 'As soon as validated', scheduled: 'Based on schedule'}}
onChange={e => setFieldValue('runType', e.target.value)}
/>
{isUpdate ??
<Input
readOnly
value={`${currentCustomer?.shortName}/${selectedPipeline?.name}`}
label="Pipeline Path"
/>}
<DateInput
name="holdPipelineStartDate"
label="Hold Start"
onChange={(_, value) => setFieldValue('holdPipelineStartDate', value)}
/>
<DateInput
name="holdPipelineEndDate"
label="Hold End"
onChange={(_, value) => setFieldValue('holdPipelineEndDate', value)}
/>
<Input
name="watchDuration"
label="File Watch Duration"
type="number"
/>
</div>
<Scheduler
schedules={values?.schedules}
setCron={(cronString, index) => {
setFieldValue(`schedules[${index}].cronExpression`, cronString);
}}
setInterval={interval => values?.schedules.forEach((_, i) => {
setFieldValue(`schedules[${i}].interval`, interval);
})}
setGrouped={isGrouped => setFieldValue('scheduleGroup', isGrouped)}
grouped={values?.scheduleGroup}
deleteSchedule={index => setValues({
...values,
schedules: values?.schedules?.filter((_, i) => i !== index)
})}
addSchedule={() => setValues({
...values,
schedules: values?.schedules?.concat({
interval: values?.schedules?.[0]?.interval ?? 'daily',
cronExpression: '0 0 * * *'
})
})}
/>
<div className="row">
<Button type="submit" color="secondary">
Save Pipeline
</Button>
<Button
isDisabled={!isUpdate}
onPress={() => setDeleteDialogOpen(true)}
>
Delete Pipeline
</Button>
</div>
</Form>
</Card>
)}
</Formik>
<p/>
{isUpdate && <FileList/>}
<ConfirmationDialog
actions={[
{
text: 'confirm',
color: 'secondary',
action: async () => {
await Pipelines.del(customerId, pipelineId);
setIds({customerId, pipelineId: undefined, fileId: undefined});
history.push(`/customers/${customerId}`);
setPipelineState();
}
},
{text: 'cancel'}
]}
open={deleteDialogOpen}
title="Delete Pipeline"
handleClose={() => setDeleteDialogOpen(false)}
>
Are you sure you want to permenantly delete this Pipeline?
</ConfirmationDialog>
</>
);
};
export default PipelineDetail;