Search code examples
javascriptreactjsformsreact-hooksuse-form

React useForm Hook with array of elemens


I have to handle a form and I'm using the useForm library of "react-hook-form", the problem is that I need to handle multiple data, such as arrays and objects, for now I've only managed to handle one array, but I can't handle two for I can't duplicate this part of the code:


const {
    register,
    handleSubmit,
    formState: { errors },
    control,
  } = useForm();

 const { fields, append, remove } = useFieldArray({
    control,
    name: "habilidades",
  });

I have this two fields:

<div>
  <label>Habilidades</label>
  {fields.map((item, index) => {
    return (
      <div key={item.id}>
        <input
          {...register(`habilidades.${index}`, { required: true })}
        />

        <button type="button" onClick={() => remove(index)}>
          Eliminar
        </button>
      </div>
    );
  })}
  <button
    type="button"
    onClick={() => {
      append("");
    }}>
    Nueva habilidad
  </button>
</div>

<div>
  <label>Aptitudes</label>

  {fields.map((item, index) => {
    return (
      <div key={item.id}>
        <input {...register(`aptitudes.${index}`, { required: true })} />

        <button type="button" onClick={() => remove(index)}>
          Eliminar
        </button>
      </div>
    );
  })}

  <button
    type="button"
    onClick={() => {
      append("");
    }}>
    Nueva habilidad
  </button>
</div>

How can I manage each of the fields independently? The problem is that it only recognizes the "habilidades" field and I need to also handle the "aptitudes" field without the two coming together.

 const { fields, append, remove } = useFieldArray({
    control,
    name: "habilidades",
    name: "aptitudes"
  });

I have tried to put two names but it does not work.

What I expect is that the form returns something like this:

{
   habilidades: ["example1", "example2", "example3"]
   aptitudes: ["example4", "example5", "example6"],
}

Solution

  • Pretty sure you need to add a useFieldArray for each array field:

    const { fields, append, remove } = useFieldArray({
        control,
        name: "habilidades",
      });
    
    const { fields: aptitudesFields, append: appendAptitudes, remove: removeAptitudes } = useFieldArray({
        control,
        name: "aptitudes"
      });
    

    Or, rather than renaming the aptitudes methods, you could use form context to split each array field into its own component where "fields", "append", and "remove" would be locally scoped.