'React-hook-form + dynamic form: Render element upon dropdown selection

I am working in form using react-hook-form. This form use useFieldArray, it has to be dynamic. Right now is very simple, it contains a react-select component with a few options and a textfield that get rendered depending on the option that the user select on the select component. The problem I have is that the textfield component renders when the state updates, which is correct until I add a new group of element to the form. Since the textfield is listening to the same state it doesn't matter which select I use to render the textfield element, it gets rendered in all groups.

I am looking a way to specify which textfield should be rendered when the user change the select.

I the sandbox you can see what I have done. To reproduce the problem click on the "Add"-button and you will see two areas, each one with a select component. When you choose "Other" in the select component a textfield appears, but not only in the area where the select was changed but in all areas.

How can I avoid that behavior?

https://codesandbox.io/s/vibrant-fast-381q0?file=/src/App.tsx

Extract:

const [isDisabled, setIsDisabled] = useState<boolean>(true);

  const { control, handleSubmit, getValues } = useForm<IFormFields>({
    defaultValues: {
      managerialPositions: [
        {
          authority: 0,
          chiefCategory: 0,
          title: 0,
          otherTitle: ""
        }
      ]
    }
  });
  

useFieldArray implementation:

const {
    fields: managerialPositionsFields,
    append: managerialPositionsAppend,
    remove: managerialPositionsRemove
  } = useFieldArray({
    name: "managerialPositions",
    control
  });

Here i update the state when the user select "Other title" in the select component:

const watchChange = (value?: number, i?: number) => {
    let values: any = getValues();

    if (values.managerialPositions[i].title === 3) {
      setIsDisabled(false);
    }
  };

And here is where I render the button to create a new group of elements and the select component and the textfield that should be rendered if "isDisabled" is false.

{managerialPositionsFields.map((field, index) => {
          return (
            <Stack className="sectionContainer" key={field.id}>
              <Stack horizontal horizontalAlign="space-between">
                <StackItem>
                  <CommandBarButton
                    iconProps={{ iconName: "AddTo" }}
                    text="Add"
                    type="button"
                    onClick={() => {
                      managerialPositionsAppend({
                        authority: 0,
                        chiefCategory: 0,
                        title: 0,
                        otherTitle: ""
                      });
                    }}
                  />
                </StackItem>
              </Stack>
              <Stack horizontal tokens={{ childrenGap: 20 }}>
                <StackItem>
                  <Label className="select-label requiredIkon">Title</Label>
                  <Controller
                    control={control}
                    name={`managerialPositions.${index}.title`}
                    render={({ field: { onChange, value, ref } }) => (
                      <>
                        <Select
                          className="react-select-container authoritySelect"
                          classNamePrefix="react-select"
                          placeholder="Select title"
                          options={titelList}
                          id={`managerialPositions.${index}.title`}
                          value={
                            titelList.find((g) => g.value === value)
                              ? titelList.find((g) => g.value === value)
                              : null
                          }
                          onChange={(val) => {
                            onChange(val.value);
                            watchChange(val.value, index);
                          }}
                        />
                        {
                          // this input is for select validation
                          <input
                            tabIndex={-1}
                            autoComplete="off"
                            style={{ opacity: 0, height: 0 }}
                            value={
                              titelList.find((g) => g.value === value)
                                ? titelList
                                    .find((g) => g.value === value)
                                    .toString()
                                : ""
                            }
                            required={true}
                            //Without this console will get an error:
                            onChange={() => {}}
                          />
                        }
                      </>
                    )}
                  />
                </StackItem>
                {!isDisabled && (
                  <StackItem className="">
                    <Controller
                      name={`managerialPositions.${index}.otherTitle`}
                      control={control}
                      render={({
                        field: { onChange, name: fieldName, value }
                      }) => (
                        <TextField
                          label="Other title"
                          name={fieldName}
                          onChange={(e) => {
                            onChange(e);
                          }}
                          value={value}
                        />
                      )}
                    />
                  </StackItem>
                )}
              </Stack>
            </Stack>
          );
        })}


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source