react-hook-form: Can't seem to update a field when using useFieldArray with setValue

Please consider asking the question at our spectrum channel.

https://spectrum.chat/react-hook-form

Describe the question?

To Reproduce Steps to reproduce the behavior:

  1. use useFieldArray
  2. try to update a certain field in all members of the array using setValue
  3. fields is out of sync with watch

Detailed explanation: I’m using useFieldArray to manage an array of objects. One of the fields in these objects has to be set manually, since it affects the other array members (it’s a toggle of who’s the primary member of the array, toggling one as the primary toggles the others off) Using setValue makes the fields object out of sync from what comes from watch.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 30 (13 by maintainers)

Most upvoted comments

I have had a similar problem: I’m using useFieldArray and watch this fields with useWatch to have changes within the fields reflected directly. When I loaded existing values from the database and populated the form via setValue, this didn’t work with array fields. The values have been set via setValue(), but they were directly overwritten due to re-renders and inconsistencies between useFieldArray fields and useWatch.

I changed my code the following way and it works now:

  • provide no default values via <Controller> component for field array fields (because they are not registered yet). I had default values for these input and when they got mounted, they were overwriting the loaded value from the database.
  • useFieldArray and useWatch to get a controlled field array. the returned fields from useFieldArray should be used as defaultValue for useWatch, e.g. `useWatch({ name: ‘parameters’ , defaultValue: fields})``
  • after data has been loaded, populate the form with reset({ ... }) instead of setValue()

I’m using "react-hook-form": "^7.6.3".

I have the same issue in nested field arrays. The top-level field array doesn’t work properly, but the second one is good with fields.

Here doesn't work the fields.map just the watched returns.
const { control, watch, getValues } = useFormContext();
const { fields, remove } = useFieldArray({
            control,
            name: 'exercises',
        });
const watchedExercises: Array<WorkoutExerciseProps> = watch('exercises');

Here works the fields.map method.
const { control, watch } = useFormContext();
const { fields, append, remove } = useFieldArray({
        control,
        name: `exercises.${exerciseIndex}.exerciseSets`,
    });

good question @Chandu here is what happened.

Because useFieldArray is relay on uncontrolled input as well (that’s why no re-render when the user is typing), so which means state lives inside inputs, this also means there are times when we need to reshuffle the inputs and potentially destroy the association between inputs, so the updated input values will be ready until the next render phase is complete, by supplied a default value with fields it close the gap with that single render.

@bluebill1049 Thanks. It worked.

@Chandu try to supply fields for the watch as default value

watch('xxx', fields') that should solve the problem.

I see. Thanks for your replies!

setValue: only trigger re-render when an error occurred or disappeared watch: re-render what’s watched.

So if, for example, I want to render for each item if its primary or not, I can’t use item.primary since that doesn’t ever gets updated, I have to use watch?