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;
关键修改点说明:
- 给
NumberFormat添加了className="form-control",和reactstrap的Input样式完全对齐 - 把
Controller的验证规则移到了rules属性中,不再使用innerRef={register}的错误写法 - 使用
render函数获取Controller提供的field对象,通过onChange同步react-hook-form的表单状态和本地的addBill状态 - 为DatePicker补充了手动触发react-hook-form变更的逻辑,确保它的必填验证也能正常触发
这样修改后,三个问题应该都能解决:样式统一、验证规则正常触发、提交时能正确获取到debitAmt的数据。
内容的提问来源于stack exchange,提问作者myTest532 myTest532
相关产品推荐
相关产品推荐

