如何在react-hook-form中向验证函数传递参数
问题描述
我正在为应用评估react-hook-form库,由于底层依赖MUI,必须使用Controller组件。希望创建通用验证规则文件供多表单复用,但需要向validate选项的函数传递动态参数:
minMaxLen需接收动态min和max值isValueEqual需要对比其他字段的值,但react-hook-form的validate回调默认仅传入当前字段值
附上现有代码:
表单组件
import React, { BaseSyntheticEvent } from 'react'; import { Controller, useForm } from 'react-hook-form'; import { ruleSet } from '../../utils/validation/rules'; import { Validate, FieldValues } from 'react-hook-form'; export const ReactHookFormSample = (): JSX.Element => { const { handleSubmit, control, formState: { errors }, getValues, register } = useForm({ mode: "onChange" }); const onSubmit = (data: any, e: BaseSyntheticEvent) => { console.log('hook form', data); } const onError = (errors: any, e: BaseSyntheticEvent) => { console.log('When errors form', errors); } const getError = (field: FieldValues) => { let errorStr = ''; let inputName = field?.name; if (errors && errors?.[inputName]) { errorStr = errors?.[inputName]?.message; } return errorStr; } return ( <> <h3>Sample React hook form</h3> <form onSubmit={handleSubmit(onSubmit, onError)}> <Controller name="user_name" control={control} rules={{ validate: {isRequired: ruleSet.isRequired, minLen: ruleSet.minLen, maxLen: ruleSet.maxLen } }} render={({ field, fieldState: {error}, formState }) => <MyTextField placeholder="Enter user name here" error={!!error} {...field} /> } /> <br/> <Controller name="password" control={control} rules={{ validate: {isRequired: ruleSet.isRequired, minLen: ruleSet.minLen, maxLen: ruleSet.maxLen } }} render={({ field, fieldState: {error}, formState }) => <MyTextField placeholder="Enter password here" error={!!error} {...field} /> } /> <br/> <Controller name="retype_password" control={control} rules={{ validate: {isRequired: ruleSet.isRequired, minMaxLen: ruleSet.minMaxLen, ruleSet.isValueEqual } }} render={({ field, fieldState: {error}, formState }) => <MyTextField placeholder="Retype password here" error={!!error} {...field} /> } /> <br/> <MyButton color="primary" type="submit"> Submit Form </MyButton> </form> </> ); };
通用规则文件
export const isRequired = (value: string) => { return value ? true : 'This is a required input, can not escape'; } export const maxLen = (value: string) => { return value.length <= 15 || 'Value cannot be more than 15 chars'; } const minLen = (value: string) => { return value.length >= 7 || 'Value cannot be less than 7 chars'; } const minMaxLen = (value: string) => { // 需要动态传入min和max参数 return value.length >= <SomeMinValue> && value.length <= <SomeMaxValue> || `Should be between ${SomeMinValue} and ${SomeMaxValue} chars`; } const isValueEqual = (value: string) => { const valOfFieldToBeComparedWith = getValues('password'); // 需动态传入要对比的字段名或getValues方法 return value === valOfFieldToBeComparedWith || 'Password and retype password do not match'; } export const ruleSet = { isRequired, minLen, maxLen, minMaxLen, isValueEqual }
解决方案
核心思路是让验证函数返回闭包,先接收动态参数,再返回实际的验证回调函数,这样就能在表单组件中灵活传入自定义参数。
1. 改造支持动态参数的验证函数
将minLen、maxLen、minMaxLen改为接收参数后返回验证函数的结构,提升通用性:
修改后的通用规则文件:
export const isRequired = (value: string) => { return value ? true : 'This is a required input, can not escape'; } // 支持动态max值 export const maxLen = (max: number) => { return (value: string) => { return value.length <= max || `Value cannot be more than ${max} chars`; } } // 支持动态min值 export const minLen = (min: number) => { return (value: string) => { return value.length >= min || `Value cannot be less than ${min} chars`; } } // 支持动态min和max值 export const minMaxLen = (min: number, max: number) => { return (value: string) => { return value.length >= min && value.length <= max || `Should be between ${min} and ${max} chars`; } } // 支持动态传入要对比的字段名和getValues方法 export const isValueEqual = (targetField: string, getValues: () => any) => { return (value: string) => { const targetValue = getValues(targetField); return value === targetValue || `Value does not match ${targetField}`; } } export const ruleSet = { isRequired, minLen, maxLen, minMaxLen, isValueEqual }
2. 表单组件中使用改造后的验证函数
在Controller的rules中,调用验证函数并传入所需的动态参数:
修改后的表单组件关键部分:
// ... 其他代码不变 return ( <> <h3>Sample React hook form</h3> <form onSubmit={handleSubmit(onSubmit, onError)}> <Controller name="user_name" control={control} rules={{ validate: { isRequired: ruleSet.isRequired, minLen: ruleSet.minLen(7), // 传入min=7 maxLen: ruleSet.maxLen(15) // 传入max=15 } }} render={({ field, fieldState: {error}, formState }) => <MyTextField placeholder="Enter user name here" error={!!error} {...field} /> } /> <br/> <Controller name="password" control={control} rules={{ validate: { isRequired: ruleSet.isRequired, minLen: ruleSet.minLen(7), maxLen: ruleSet.maxLen(15) } }} render={({ field, fieldState: {error}, formState }) => <MyTextField placeholder="Enter password here" error={!!error} {...field} /> } /> <br/> <Controller name="retype_password" control={control} rules={{ validate: { isRequired: ruleSet.isRequired, minMaxLen: ruleSet.minMaxLen(7,15), // 传入min=7,max=15 isValueEqual: ruleSet.isValueEqual('password', getValues) // 传入目标字段名和getValues方法 } }} render={({ field, fieldState: {error}, formState }) => <MyTextField placeholder="Retype password here" error={!!error} {...field} /> } /> <br/> <MyButton color="primary" type="submit"> Submit Form </MyButton> </form> </> );
补充说明
- 闭包的方式可以让验证函数在定义时捕获动态参数,在实际验证时使用这些参数进行判断
- 跨字段验证时,通过传入
getValues方法,验证函数可以灵活获取任意字段的值,不需要硬编码字段名 - 所有验证函数保持了通用性,可在其他表单中重复调用,只需传入不同的参数即可
内容的提问来源于stack exchange,提问作者WomenInTech
相关产品推荐
相关产品推荐

