You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免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钩子缓存生成的验证规则,仅在依赖项变化时重新生成:

  1. 导入useMemo:
import { useMemo } from 'react';
  1. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 16:01:30