React Hook Form:onChange前输入验证的更优方案探讨
优化React Hook Form数字输入验证的几种方案
你的代码思路没问题,但可以从减少冗余逻辑、利用RHF原生能力这两个方向优化,下面是几种更简洁的实现方式:
方案1:用Controller的transform属性替代自定义onChange
React Hook Form的Controller自带transform属性,专门用来在值提交到表单前做转换/过滤,不用手动在onChange里处理,代码更规整:
<Controller control={control} name="nik" rules={PERSONAL_INFORMATION_FORM_SCHEMA.nik} // 直接在这里过滤非数字字符 transform={(value) => value.replace(/[^0-9]/g, '')} render={({ field }) => ( <TextField {...field} error={!!errors?.nik} helperText={errors.nik?.message} id="nik" placeholder={t("personalInformationInputIDNumberPlaceholder")} type="text" inputProps={{ maxLength: 16, inputMode: "numeric", // 移动端弹出数字键盘,体验更好 pattern: "[0-9]*" // 配合HTML5原生验证 }} // 这里不用再自定义onChange,直接用field.onChange即可 /> )} />
优势:把输入过滤逻辑和组件渲染逻辑分离,符合RHF的设计思路,代码更清晰。
方案2:在onChange内直接处理,简化逻辑
如果不想用transform,也可以把过滤逻辑直接写在onChange里,省去单独的validateInput函数:
<Controller control={control} name="nik" rules={PERSONAL_INFORMATION_FORM_SCHEMA.nik} render={({ field }) => ( <TextField {...field} error={!!errors?.nik} helperText={errors.nik?.message} id="nik" placeholder={t("personalInformationInputIDNumberPlaceholder")} type="text" inputProps={{ maxLength: 16, inputMode: "numeric" }} onChange={(e) => { // 直接过滤非数字后传给field.onChange const filteredValue = e.target.value.replace(/[^0-9]/g, ''); field.onChange(filteredValue); }} /> )} />
优势:逻辑更直观,适合快速修改,不需要额外理解transform的用法。
方案3:结合HTML5特性+RHF规则双重保障
如果想要更严格的验证,可以把前端输入过滤和RHF的rules结合,比如在rules里添加正则验证,确保即使前端过滤失效(比如通过控制台修改值),表单提交时也会拦截:
假设你的PERSONAL_INFORMATION_FORM_SCHEMA.nik可以这么定义(以常规规则为例):
const PERSONAL_INFORMATION_FORM_SCHEMA = { nik: { required: "请输入身份证号", pattern: { value: /^[0-9]{1,16}$/, message: "请输入有效的16位数字" } } };
然后配合前端的输入过滤,这样前端实时过滤,提交时再做一次校验,双重保险。
避坑提醒
- 不要用
type="number":虽然会弹出数字键盘,但它允许输入小数点、正负号,而且对于超长数字(比如16位身份证)会自动转成科学计数法,反而麻烦。 inputMode="numeric"是更好的选择:移动端会弹出纯数字键盘,同时输入框还是文本类型,不会有科学计数法的问题。
内容的提问来源于stack exchange,提问作者aksal
相关产品推荐
相关产品推荐

