我正在使用 React Typescript 构建带有 Zod 验证模式的表单。
我想要实现什么? 因此,我想根据另一个字段的值呈现条件。每个国家/地区都有自己的电话代码和电话号码格式。每次有人选择电话号码时,我希望电话号码字段具有不同的验证规则。这是我到目前为止所拥有的。这基本上是我实际项目的复制。
import { Formik, Field, Form, FormikHelpers } from 'formik'
import { toFormikValidationSchema } from 'zod-formik-adapter'
import { z } from 'zod'
import './App.css'
const FormField = z.object({
firstName: z.string().max(6, 'Too long'),
lastName: z.string(),
email: z.string(),
phoneCode: z.string(),
phoneNumber: z.string()
})
const Register = FormField.required()
.refine((input) => {
return input.phoneCode === '0044';
}, 'Phone code must be 0044');
Register.parse({
firstName: 'fewfwf',
lastName: 'Doe',
email: '[email protected]',
phoneCode: '0044',
phoneNumber: '0044'
})
type Values = z.infer<typeof Register>
function App() {
return (
<>
<Formik
initialValues={{
firstName: '',
lastName: '',
email: '',
phoneCode: '',
phoneNumber: ''
}}
onSubmit={(
values: Values,
{ setSubmitting }: FormikHelpers<Values>
) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
setSubmitting(false);
}, 500);
}}
validationSchema={toFormikValidationSchema(FormField)}
>
{({ errors, touched }) => (
<Form>
{errors.firstName ? (<div>{errors.firstName}</div>) : null}
<label htmlFor="firstName">First Name</label>
<Field id="firstName" name="firstName" placeholder="John" />
<label htmlFor="lastName">Last Name</label>
<Field id="lastName" name="lastName" placeholder="Doe" />
<label htmlFor="email">Email</label>
<Field
id="email"
name="email"
placeholder="[email protected]"
type="email"
/>
<label htmlFor="phoneCode">PhoneCode</label>
<Field id="phoneCode" name="phoneCode" placeholder="+44" />
{errors.phoneNumber && touched.phoneNumber ? (<div>{errors.phoneNumber}</div>) : null}
<label htmlFor="phoneNumber">PhoneNumber</label>
<Field id="phoneNumber" name="phoneNumber" placeholder="789434556" />
<button type="submit">Submit</button>
</Form>
)}
</Formik>
</>
)
}
export default App
如您所见,我使用了 .refine() 并添加了一些随机条件来测试。当我通过解析方法运行它时,它会正确验证并工作,但是,当我从前端提交表单时,它仍然会执行,即使phoneCode不等于“0044”。这是 .refine 方法的正常行为吗?还有其他更实用的方法吗?
Zod 中的
.refine()
方法用于在解析阶段应用自定义细化检查。它确保输入满足指定的条件,如果不满足则抛出错误。但是,当您同时使用 Formik 和 Zod 时,您可能希望以不同的方式处理这些动态验证规则。
在您的情况下,您希望根据所选的电话代码值有条件地验证电话号码字段。为此,您可以对验证模式中的各个字段使用细化方法,并在细化函数内执行条件检查。但是,请记住,细化函数是在解析阶段评估的,并且不会自动应用到 Formik 上下文中
import { Formik, Field, Form, FormikHelpers } from 'formik';
import { toFormikValidationSchema } from 'zod-formik-adapter';
import { z } from 'zod';
import './App.css';
const FormField = z.object({
firstName: z.string().max(6, 'Too long'),
lastName: z.string(),
email: z.string(),
phoneCode: z.string(),
phoneNumber: z
.string()
.refine((value, data) => {
// Perform your dynamic validation based on phoneCode
return data.phoneCode === '0044' ? value.length === 10 : true;
}, 'Invalid phone number length'),
});
type Values = z.infer<typeof FormField>;
function App() {
return (
<>
<Formik
initialValues={{
firstName: '',
lastName: '',
email: '',
phoneCode: '',
phoneNumber: '',
}}
onSubmit={(
values: Values,
{ setSubmitting }: FormikHelpers<Values>,
) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
setSubmitting(false);
}, 500);
}}
validationSchema={toFormikValidationSchema(FormField)}
>
{({ errors, touched }) => (
<Form>
{errors.firstName ? <div>{errors.firstName}</div> : null}
<label htmlFor="firstName">First Name</label>
<Field id="firstName" name="firstName" placeholder="John" />
<label htmlFor="lastName">Last Name</label>
<Field id="lastName" name="lastName" placeholder="Doe" />
<label htmlFor="email">Email</label>
<Field
id="email"
name="email"
placeholder="[email protected]"
type="email"
/>
<label htmlFor="phoneCode">PhoneCode</label>
<Field id="phoneCode" name="phoneCode" placeholder="+44" />
{errors.phoneNumber && touched.phoneNumber ? (
<div>{errors.phoneNumber}</div>
) : null}
<label htmlFor="phoneNumber">PhoneNumber</label>
<Field
id="phoneNumber"
name="phoneNumber"
placeholder="789434556"
/>
<button type="submit">Submit</button>
</Form>
)}
</Formik>
</>
);
}
export default App;
这样就对phoneNumber字段使用了
.refine()
方法,根据phoneCode进行动态验证。根据您的具体验证逻辑调整细化函数内的条件。
这样,验证将在解析阶段应用,如果不满足条件,您将看到错误消息。