javascripttypescriptreact-hook-form

useFormContext()'s watch not triggering a re-render


In a const component, I have this watch configured:

const { watch, setValue, control } = useFormContext<QuoteCalculatorValues>();
const fuelCostWatch = watch('fees')?.['fuel_costs']?.[0];
const watchPath = `fees.[fuel_costs][0].`;

'fees' is a key/value array, with the following:

export type FormPayableAccessoryFeeDto = {
    quantity: number;
    rate: number;
};

export interface FormPayableAccessoryFeeIndexDto {
    [key: string]: FormPayableAccessoryFeeDto[] | undefined;
}

export type QuoteCalculatorValues = {
    fees: FormPayableAccessoryFeeIndexDto;
};

Here's an input I configured to be monitored by the watch

<Controller
  name={`fees.[fuel_costs][0].quantity`}
  control={control}
  render={({ field }) => (
    <Input
      field={field}
      defaultValue={0}
      onChange={value => {
        setValue(`fees.[fuel_costs][0].quantity`, value as never);
      }}
    />
  )}
/>

I'm expecting that because I'm watch'ing values in fee, when I change the value in the input, the component should re-render.

One thing I noticed, is that in onChange, I have to cast value as never, which might indicate a problem I guess?

I tested this with a more basic structure (i.e. if I watch('info') and create an input on info.firstName) and this works.

Is there a problem with the way my form data's structured?

It works if I configure the watch to listen to the entire form, but I'm worried that might slow things down a bit if arrays get populated with a lot of data (i.e. if I have more indices than fuel_costs).

const fuelCostWatch = watch().fees['fuel_costs']?.[0];

Solution

  • Try watching your property like this

    const fuelCostWatch = watch('fees.fuel_costs.0');
    

    Instead of

    const fuelCostWatch = watch('fees')?.['fuel_costs']?.[0];