问题描述
我正在使用 Yup 验证和 formik。我准备了初始值和validationSchema,并且在创建表单期间一切正常。但是在更新表单时,即使在各自的字段中预先填充了值,仍有一些字段显示“需要 abc 字段”。 (根据以下问题,名称和类型字段是必需的)
const initialValues = {
type: '',name: '',detail: {
shareDetail: {
tenantId: '',username: ''
},blobDetail: {
access: '',connection: ''
}
}
}
const validationSchema = Yup.object().shape({
name: Yup.string().required(),type: Yup.string().required(),detail: Yup.object().required().when('type',{
is: (selectedType) => selectedType === 'SHARE',then: Yup.object({
shareDetail: Yup.object({
tenantId: Yup.string().required(),username: Yup.string().required()
})
}),is: (selectedType) => selectedType === 'BLOB',then: Yup.object({
blobDetail: Yup.object({
access: Yup.string().required(),connection: Yup.string().required()
})
})
})
},['type'])
我的 jsx 是:
<Formik initialValues={formData || initialValues} validationSchema={validationSchema} onSubmit={onSubmit} enableReinitialize validateOnMount>
{formik => {
return (
<Form>
<h5>Source</h5>
<div className='row'>
<div className='col-6'>
<FormControl control='select' label='Type *' placeholder='Enter Source Type' name='type' options={sourceTypes} AutoComplete
value={getSourceTypeValue(formik.values.type)} onChange={e => handleSourceTypeSelect(e,formik.setFieldValue)} onBlur={() => handleSourceTypeBlur(formik.setFieldTouched)}
outlineDanger={formik.errors.type && formik.touched.type ? 'mnd-danger' : ''} isdisabled={type !== 'createSourceButton'} />
</div>
<div className='col-12 mt-2'>
<FormControl control='input' type='text' label='Name *' placeholder='Enter Source Name' name='name'
version={formik.touched.name && formik.errors.name ? 'mnd-danger' : ''} disabled={type !== 'createSourceButton'} />
</div>
<div className='col-12'>
<FormControl control='textarea' type='text' placeholder='Enter Source Description' label='Source Description' rows='3' name='description' />
</div>
</div>
<hr />
{formik.values.type === 'SHARE' && <>
<h5>Source Details</h5>
<div className="row mt-3">
{type === 'createSourceButton' && <div className="col-6 mt-2">
<FormControl control='input' type='text' label='Tenant Id *' placeholder='Enter Tenant Id' name='detail.shareDetail.tenantId'
version={formik.touched.detail && formik.errors.detail && formik.touched.detail.shareDetail.tenantId && formik.errors.detail.shareDetail.tenantId ? 'mnd-danger' : ''} />
</div>}
<div className="col-6">
<FormControl control='input' type='text' label='Username *' placeholder='Enter Username' name='detail.shareDetail.username'
version={formik.touched.detail && formik.errors.detail && formik.touched.detail.shareDetail.username && formik.errors.detail.shareDetail.username ? 'mnd-danger' : ''} />
</div>
</div>
<hr />
</>}
{formik.values.type === 'BLOB' && <>
<h5>Source Details</h5>
<div className="row mt-3">
<div className="col-12">
<FormControl control='textarea' type='text' label='Connection String *' placeholder='Enter Connection String' rows='3' name='detail.blobDetail.connection'
variant={formik.touched.detail && formik.errors.detail && formik.touched.detail.blobDetail.connectionString && formik.errors.detail.blobDetail.connectionString ? 'mnd-danger' : ''} />
</div>
<div className="col-12">
<FormControl control='select' label='Access *' placeholder='Select Access' name='detail.blobDetail.access' options={accessOptions}
value={getAccesstierValue(formik.values.detail.blobDetail.accesstier)} onChange={e => handleAccesstierSelect(e,formik.setFieldValue)} onBlur={() => handleAccesstierBlur(formik.setFieldTouched)}
outlineDanger={formik.touched.detail && formik.errors.detail && formik.touched.detail.blobDetail.access && formik.errors.detail.blobDetail.access? 'mnd-danger' : ''} />
</div>
</div>
<hr />
</>}
<div className="btn-toolbar float-right" role="toolbar">
<div className="btn-group mr-2" role="group">
<Button variant='outline' onClick={() => handleCancel()}>Cancel</Button>
</div>
<div className="btn-group mr-2" role="group">
{type === 'createSourceButton' && <Button type='reset' onClick={() => resetForm()}>Reset</Button>}
</div>
<div className="btn-group" role="group">
<Button type='submit' disabled={!formik.isValid} onSubmit={() => onSubmit()}>
{type === 'createSourceButton' ? 'Create' : 'Update'}
</Button>
</div>
</div>
</Form>
)
}}
</Formik>
在源创建场景中一切正常,但更新按钮被禁用,如果我检查 formik 错误,它会说名称和类型是必填字段,即使它们各自的值在 UI 中正确填充。
解决方法
在定义初始值的过程中,您已经为 detail
属性的两种情况设置了所有道具,这会导致类型属性的每个值出现问题,这两个属性仍将存在于主对象上.
您可能想尝试以下操作:
const initialValues = {type: '',name: '',detail:{}};
const validationSchema = Yup.object().shape({
name: Yup.string().required(),type: Yup.string().required(),detail: Yup.object().when('type',{
is: (selectedType) => !!selectedType && selectedType === 'SHARE',then: Yup.object.shape({
shareDetail:Yup.object().shape({
tenantId: Yup.string().required(),username: Yup.string().required()
})
}),is: (selectedType) => !!selectedType && selectedType === 'BLOB',then: Yup.object.shape({
blobDetail: Yup.object().shape({
access: Yup.string().required(),connection: Yup.string().required()
})
}),}).nullable().required() // you might also need this.
}); //,['type'])
问题可能出在您传递给 enableReinitialize
的 formik
道具上。在文档状态中:
启用重新初始化?:布尔值
默认为假。控制是否Formik 如果 initialValues 更改(使用深度相等),则应重置表单。
https://formik.org/docs/api/formik#enablereinitialize-boolean