如何避免Formik表单每次按键时重新生成Yup验证规则
问题描述
我正在使用Formik的useFormik()管理表单状态,通过Yup实现验证。部分表单字段存在依赖关系,因此需要动态生成验证规则。当前代码运行正常,包括依赖字段验证和Formik状态管理,但每次按键时,验证规则生成函数generateFormikValidationSchema都会被调用,我希望该规则仅在页面首次加载时生成,寻求解决方案。
相关代码如下:
// 主视图中创建Formik和验证规则 const EntityView = (props) => { const formik = useFormik({ initialValues: { properties: [ // ... 描述表单字段及验证规则的对象数组 ] // ... }, onSubmit: () => { }, // 注意!动态生成的验证规则 validationSchema: generateFormikValidationSchema(allEntityProperties), validateOnChange: true, }) return ( <div className="space-y-20"> {formik.values.properties.map(property => { switch (property.type) { case "number": return <Input name={property.name} value={/* 关联的Formik值*/} onChange={formik.handleChange} ... /> case "textarea": return <Textarea name={property.name} value={/* 关联的Formik值*/} onChange={formik.handleChange} ... /> } })} </div> ) } // 动态生成验证规则的方法 const generateFormikValidationSchema = properties => { console.log(" regenerating ...") // ! <---------- 此处每次按键都会打印 const shape = {} properties.forEach(prop => { if (prop.details.is_required) { switch (prop.details.type) { case "number": shape[prop.id] = yup.number() .min(1, "must be greater than 1") .max(49, "must be less than 50") .required("majburiy maydon") .when(["a"], (reliantProp, schema) => { let newRule = undefined // 简化代码,省略部分逻辑 switch (otherFieldValue) { ... } return newRule }) break case "textarea": ... } } }) return yup.object().shape({ properties: yup.object(shape) }) }
解决方案
问题根源在于每次组件渲染(比如输入框触发状态更新)时,useFormik的配置对象会被重新创建,导致generateFormikValidationSchema被重复调用。可以用React的useMemo钩子缓存生成的验证规则,仅在依赖项变化时重新生成:
- 导入
useMemo:
import { useMemo } from 'react';
- 在
EntityView组件内,用useMemo包裹验证规则生成逻辑,依赖allEntityProperties:
const EntityView = (props) => { // 缓存验证规则,仅在allEntityProperties变化时重新生成 const validationSchema = useMemo(() => { return generateFormikValidationSchema(allEntityProperties); }, [allEntityProperties]); const formik = useFormik({ initialValues: { properties: [ // ... 描述表单字段及验证规则的对象数组 ] // ... }, onSubmit: () => { }, validationSchema: validationSchema, // 使用缓存后的规则 validateOnChange: true, }) // ... 其余代码不变 }
原理说明
useMemo会缓存函数的返回值,只有当依赖数组中的值发生变化时,才会重新执行函数生成新结果。- 如果
allEntityProperties是页面初始化时确定的静态数据,验证规则只会在组件首次渲染时生成一次,后续输入触发的渲染会直接使用缓存规则,避免重复调用生成函数。 - 如果
allEntityProperties后续需要更新(比如异步接口返回),依赖数组会自动触发规则重新生成,保证验证逻辑的正确性。
内容的提问来源于stack exchange,提问作者ABDULLOKH MUKHAMMADJONOV
相关产品推荐
相关产品推荐

