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

React Hook Form中useFormContext的watch监听嵌套表单结构未触发组件重渲染问题

React Hook Form中useFormContext的watch监听嵌套表单结构未触发组件重渲染问题

嘿,我来帮你排查下这个React Hook Form的监听问题~

首先,你的核心问题出在watch的监听方式和表单字段路径的写法上,另外TypeScript里的as never强制转换也确实是个信号,说明路径写法不符合React Hook Form的规范,咱们一步步来解决:

1. 问题根源:错误的字段路径与监听逻辑

你在Controller的name里写了fees.[fuel_costs][0].quantity,还有watch里先监听整个fees再链式取值的方式都有问题:

  • React Hook Form的字段路径语法中,对象的键不需要用方括号包裹(动态键场景更推荐用数组形式路径),正确的路径应该是fees.fuel_costs[0].quantity或者数组形式['fees', 'fuel_costs', 0, 'quantity']。
  • 直接watch('fees')只会在fees对象的引用发生变化时触发重渲染,而嵌套字段(比如fuel_costs[0].quantity)的更新并不会改变fees的引用,所以组件不会重新渲染。

2. 修正后的代码示例

调整watch的监听逻辑

直接监听目标嵌套路径,用数组形式的路径更利于TypeScript类型推断,也更可靠:

const { watch, control } = useFormContext<QuoteCalculatorValues>();
// 数组形式监听精准路径
const fuelCostWatch = watch(['fees', 'fuel_costs', 0]);
// 或者字符串形式
// const fuelCostWatch = watch('fees.fuel_costs[0]');

修正Controller的配置

另外你在Input的onChange里手动调用setValue是多余的——Controller的field已经包含了正确的 onChange 逻辑,直接传给Input即可,同时修正name的写法:

<Controller
  name={['fees', 'fuel_costs', 0, 'quantity']} // 数组路径让类型推断更准确
  control={control}
  render={({ field }) => (
    <Input
      field={field}
      defaultValue={0}
      // 去掉多余的手动setValue,field.onChange已经会处理值更新
    />
  )}
/>

这样修改后,当你修改Input的值时,watch监听的fees.fuel_costs[0]会检测到变化并触发组件重渲染,同时TypeScript的类型错误也会消失,不需要再用as never强制转换了。

3. 为什么监听整个表单有效?

当你用watch().fees['fuel_costs']?.[0]时,watch()没有传参数,会监听所有表单字段的变化,只要任何字段更新都会触发重渲染,所以能看到效果。但这种方式在表单数据量大时确实会有性能隐患,而精准监听特定路径就能避免这个问题。

备注:内容来源于stack exchange,提问作者Francis Ducharme

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.13 18:24:34