The fieldArray structure and methods on useForm()

The useFieldArray hook allows us to render and update inputs in a dynamic form, improving user experience and performance.

Its properties are:

  • name: The fieldArray name, it's used to set the fieldArray's defaultValues in useForm().

  • control: Its useForm() control property.

  • shouldUnregister: boolean; it indicates whether the elements of the fieldArray should be unregistered after unmounting. False by default.

  • rules: Its validation rules apply to the number of objects in the field array, rather than to the individual input values.

The useFieldArray() hook returns an array of input fields objects, each with a unique ID. In the DOM, we map() the fieldsArray, using its item.id as the container key attribute, and its properties to render the inputs of the current index item.

We render index input errors with a ternary operator on the formState.errors or directly rendering its message by using optional chaining (?.).

This approach avoids the 'Cannot read properties of undefined' error that returns on an empty errors object.//The rules errors can block submit and are found in at errors._arrayName_.root

//The rendered inputs names need to correspond to the defaultValues(if set)
const {register, control, formState: {errors}} = useForm({
  defaultValues: {
    basic: "primo", 
    domandad: [{primo: "valore", second: "self select"}]
  }
})

const {fields, append} = useFieldArray({
  control: control, name: "domandad",
  rules: { minLength: { value: 4, message: "Its too short" } }
})

<form>
  <input {...register("basic")} />

  <ul>
  {fields.map((item, index)=>{
    return(
      <li key={item.id}>
        <input {...register(`domandad.${index}.primo`,{required: "missing"})}/>
        <input {...register(`domandad.${index}.second`, 
          {minLength: {value: 10, message: "too shorty"}}) }
        />

        <p> { errors?.domandad?.[index]?.primo?.message } </p>
	<p> { errors.domandad&& errors.domandad[index]?.name.message } </p>
      </li>
    )
  })
  }
  </ul>

  <p> { errors.domandad?.root.message } </p>
</form>

The arrayFields errors property will be an array of error objects, with each error corresponding to its input based on its index.

Any useFieldsArray method object will have to match the number and names of the fields.map() inputs.

The fieldArray inputs can be rendered using different components.

The useFieldArray() methods

The fieldArray returns include the methods to edit the rendered field object:

chevron-rightuseFieldArray methods hashtag
  • append: object. It adds a new input object at the end of the fieldArray.

  • remove: index. It removes the fieldArray object with the index.

  • insert: index, object. It adds the input object to the set fieldsArray index.

  • prepend: object. It places the input object at the start of the fieldArray.

  • swap: 2 index. It swaps the position of the 2 pre-existent input objects.

  • move: 2 index. It moves the index input position to the target position, moving the inbetween inputs by 1.

  • update: index, object. It updates the value of its specific index input object.

  • replace: object/array. It will replace the entire fieldArray, use an array for multiple input objects.

All useFieldArray() methods focus the input indexes they apply to. The append, prepend, and insert methods include optional properties, shouldFocus and focusIndex, which determine whether to focus its object index or a specific input object in the fieldArray.

Do not stack useFieldArray methods; instead, we useEffect() to sequentially trigger methods based on specific useState dependencies.

The fieldArray inputs and values rules on useForm() render

The fieldArray <input> index can be used to conditionally render an input or dynamically modify the form based on the input's position.

A useFieldArray will automatically create its array even without defaultValues when input objects are added.

We useWatch() the <input> index value as condition to render the specific <input> property. Any added input property will be returned by the onSubmit function, even if it is not rendered. The static form ensures that only one conditional input will be rendered at a time.

Conditional Input component with fieldArray methods

The fieldArray will batch updates during the component's re-render, and any functions that access it will retrieve the last rendered form object.

We create an object that merges the fieldArray with its watch() current values, allowing us to have the complete field values available.

A fieldArray form with nested useForm() components.

We render a parent fieldArray useForm() with a nested useForm() component.

The nested component <Singular> will render and register the fieldArray input objects, and onSubmit() it will update the parent fieldArray, using the index and useFieldArray() update props

chevron-rightThe useWatch() hook update on different useForm() control object propertieshashtag

A custom hook (like useWatch()) will update based on the useForm() structure of its control property.

The parent useForm() will get updated based on its fieldArray structure, not its field values. The child useForm() registers the inputs, so its control will trigger the useWatch() on input change to return the current field values.

We use a ternary operator useWatch() name to specify the input index being watched, an undefined name would return the entire form, so we use a non-existent input name.

The third child component <Risulta> will be conditionally rendered based on its index input values. It will be re-rendered each time the fieldArray is updated due to the useWatch() control property.

Append and render fieldArray input object components

1

Last updated