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

react-hook-form集成react-number-format问题:样式不一致、校验失效及提交数据缺失

解决react-number-format结合react-hook-form的三个问题

我来帮你搞定这三个问题,咱们逐个击破:

1. 样式不一致问题

react-number-format组件默认没有reactstrap Input的样式,只需要给它加上reactstrap的form-control类名,就能和其他输入框的样式统一了。

2. 无法触发错误校验 & 3. 提交后无debitAmt数据问题

这两个问题的根源在于没有正确使用react-hook-form的Controller组件:

  • 不能直接把register放到innerRef里,Controller本身负责表单字段的注册和验证,应该用rules属性设置验证规则
  • 需要通过Controller提供的field对象同步值和变更事件,确保react-hook-form能捕获到字段的正确值

修改后的完整代码

import React, { useState } from 'react';
import { Controller, useForm } from "react-hook-form";
import { Form, Label, Input, Button } from 'reactstrap';
import { FormGroup } from '@material-ui/core';
import moment from 'moment';
import DatePicker from "reactstrap-date-picker";
import NumberFormat from 'react-number-format';

const setErrorStyle = (name) => {
 return {
 borderColor: name ? 'red' : '',
 boxShadow: name ? '0 0 1.5px 1px red' : ''
 }
}

const Test = () => {
 const [ addBill, setAddBill ] = useState({
 debitAmt: '',
 invoiceNumber: '',
 memo: '',
 invoiceDate: moment().format('YYYY-MM-DD'),
 });

 const { register, handleSubmit, errors, control } = useForm({
   defaultValues: {
     debitAmt: addBill.debitAmt,
     invoiceNumber: addBill.invoiceNumber,
     memo: addBill.memo,
     invoiceDate: addBill.invoiceDate
   }
 });

 const submitAddBill = (data) => {
 console.log(data); // 现在能正常拿到debitAmt字段数据了
 }

 return (
 <>
 <Form onSubmit={handleSubmit(submitAddBill)}>
 <div className="row">
 <div className="col-sm-2">
 <FormGroup className="mr-10 mb-10">
 <Label for="debitAmt" className="mr-sm-10">Debit Amt</Label>
 <Controller
   name="debitAmt"
   control={control}
   rules={{ required: true }} // 在这里设置验证规则
   render={({ field: { onChange, value, ref } }) => (
     <NumberFormat
       thousandSeparator={true}
       prefix="$"
       value={value} // 使用Controller提供的value
       onChange={(values) => {
         // 同时更新react-hook-form的表单状态和本地state
         const inputValue = values.floatValue === undefined ? '' : values.floatValue;
         onChange(inputValue);
         setAddBill(prev => ({...prev, debitAmt: inputValue}));
       }}
       ref={ref} // 传递Controller的ref
       className="form-control" // 加上reactstrap的样式类
       style={setErrorStyle(errors.debitAmt)}
     />
   )}
   aria-invalid={errors.debitAmt ? "true" : "false"}
 />
 {errors.debitAmt && (
 <span style={{ color: "red" }} role="alert">required</span>
 )}
 </FormGroup>
 </div>
 <div className="col-sm-2">
 <FormGroup className="mr-10 mb-10">
 <Label for="invoiceDate" className="mr-sm-10">Invoice Date</Label>
 <DatePicker
 name="invoiceDate"
 id="invoiceDate"
 value={addBill.invoiceDate}
 onChange={(e) => {
   const formattedDate = e ? moment(e).format('YYYY-MM-DD') : '';
   setAddBill({...addBill, invoiceDate: formattedDate});
   // 手动触发react-hook-form的变更,确保验证正常触发
   register('invoiceDate').onChange({target: {name: 'invoiceDate', value: formattedDate}});
 }}
 innerRef={register({ required: true })}
 aria-invalid={errors.invoiceDate ? "true" : "false"}
 style={setErrorStyle(errors.invoiceDate)}
 />
 {errors.invoiceDate && (
 <span style={{ color: "red" }} role="alert">required</span>
 )}
 </FormGroup>
 </div>
 <div className="col-sm-3">
 <FormGroup className="mr-10 mb-10">
 <Label for="invoiceNumber" className="mr-sm-10">Invoice Number</Label>
 <Input
 type="text"
 name="invoiceNumber"
 id="invoiceNumber"
 placeholder="1234567"
 innerRef={register({ required: true })}
 aria-invalid={errors.invoiceNumber ? "true" : "false"}
 value={addBill.invoiceNumber}
 onChange={(e) => setAddBill({...addBill, invoiceNumber: e.target.value})}
 style={setErrorStyle(errors.invoiceNumber)}
 />
 {errors.invoiceNumber && (
 <span style={{ color: "red" }} role="alert">required</span>
 )}
 </FormGroup>
 </div>
 <div className="col-sm-3">
 <FormGroup className="mr-10 mb-10">
 <Label for="memo" className="mr-sm-10">Memo</Label>
 <Input
 type="text"
 name="memo"
 id="memo"
 placeholder="Memo"
 innerRef={register()}
 aria-invalid={errors.memo ? "true" : "false"}
 value={addBill.memo}
 onChange={(e) => setAddBill({...addBill, memo: e.target.value})}
 style={setErrorStyle(errors.memo)}
 />
 </FormGroup>
 </div>
 </div>
 <Button type="submit" color="primary" size="sm" className="w-auto">Add Bill</Button>
 </Form>
 </>
 )
}

export default Test;

关键修改点说明:

  1. 给NumberFormat添加了className="form-control",和reactstrap的Input样式完全对齐
  2. 把Controller的验证规则移到了rules属性中,不再使用innerRef={register}的错误写法
  3. 使用render函数获取Controller提供的field对象,通过onChange同步react-hook-form的表单状态和本地的addBill状态
  4. 为DatePicker补充了手动触发react-hook-form变更的逻辑,确保它的必填验证也能正常触发

这样修改后,三个问题应该都能解决:样式统一、验证规则正常触发、提交时能正确获取到debitAmt的数据。

内容的提问来源于stack exchange,提问作者myTest532 myTest532

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 13:57:42