useForm表单小数值校验触发异常问题求助
问题核心原因
- 类型不匹配:表单字段默认将输入框onChange返回值识别为字符串类型,但初始化传入的是decimal/number类型的
6.77。useForm做值比对时,"6.77" !== 6.77,只要触发输入动作拿到字符串类型值,就会和初始值的number类型判定为不一致,直接触发校验报错。 - 校验触发逻辑配置问题:如果将校验触发模式设为
onChange,且没有配置值类型自动转换逻辑,每一次输入字符变更都会立刻执行校验,无需等失焦或提交动作。 - 浮点数精度问题:decimal类型转JS原生number时本身存在精度丢失,比如
6.77实际存储值可能为6.7700000000000005,哪怕手动输入6.77转成number,和初始decimal值做全等判断也会被判定为不相等。
修复方案
- 统一表单值类型
初始化赋值时就把decimal类型默认值转成字符串,和输入框返回的字符串类型保持一致,不要在表单状态里混存number和string两种类型的值:const form = useForm({ defaultValues: { // decimal值提前转字符串,和输入值类型对齐 amount: decimalDefaultValue.toString() } }) - 按需做类型转换
表单状态层面统一存字符串类型,等提交取值时再转回业务需要的decimal/number类型即可:const handleSubmit = (formValues) => { // 提交阶段再做类型转换,不干扰表单内部的值比对逻辑 const submitParams = { amount: new Decimal(formValues.amount) } // 执行后续提交逻辑 } - 调整校验触发时机(可选)
如果不需要输入时立刻弹出错误,可以把校验模式改成失焦触发,减少输入过程中的无效打断:const form = useForm({ mode: 'onBlur', // 替换默认的onChange触发逻辑 defaultValues: { amount: decimalDefaultValue.toString() } }) - 特殊场景适配:如果必须在表单状态中存number/decimal类型,注册字段时要配置值转换规则
通过setValueAs配置项,把输入的字符串自动转换成对应类型,保证和初始值类型完全一致:<input {...register('amount', { // 转number可以直接用内置配置 // valueAsNumber: true, // 转decimal类型自定义转换逻辑 setValueAs: (inputVal) => new Decimal(inputVal) })} />
注意:判断两个decimal值是否相等时,不要直接用
===做全等判断,要调用decimal实例自带的.equals()方法,否则浮点数精度问题会持续导致值校验判定异常。
内容的提问来源于stack exchange,提问作者Minh Lưu
相关产品推荐
相关产品推荐

