React Hook Formを親子コンポーネントで使用する

に公開

今回は繰り返し使用するようなコンポーネントの中でReact Hook Formを使用する際のポイントをまとめていきます。
※ MUIはv5 / react-hook-form v7 になります

(1)イメージ図

下の画像のように(親)コンポーネント内に共通の(子)コンポーネントが2つある

(2)親コンポーネントの準備

親コンポーネントでやることは以下のことです。
①useFormを呼び出し、"useFormMethods"(こちらの命名はご自由に)に格納
※defaultValuesやrezolver(zod)の登録もここでしておく
②useFormMethodsからhandlSubmitを使用できるようにしておく。
③FormProviderでform全体を囲っておく。FormProviderに先ほど用意した"useFormMethods"を渡しておく

フォームの項目は今回は「title」と「description」を作成。
それぞれ子コンポーネントにpropsとして渡しておきます。

const ParentChild = () => {
  // ①useFormを呼び出し
  const useFormMethods = useForm({
    defaultValues: {
      title: '',
      description: ''
    }
  });

  // ②使用するメソッドを取り出す
  const {
    handleSubmit
  } = useFormMethods;

  const onSubmit = (data: Inputs) => {
    console.log(data);
  };

  return (
    // ③FormProvierで囲っておく
    <FormProvider {...useFormMethods}>
      <Stack m={4} component="form" noValidate onSubmit={handleSubmit(onSubmit)}>
        <TextFieldcontrol name="title" />
        <TextFieldcontrol name="description" />
        <Box mt={2}>
          <Button type="submit" color="secondary" variant="contained">
            送信
          </Button>
        </Box>
      </Stack>
    </FormProvider>
  );
};

export default ParentChild;


以上になります。

(3)子コンポーネントの準備

TextFieldControlという名前の子コンポーネントを用意します。
この中ではやることは以下のことです。

①useFormContextを呼び出し、controlを使用できるようにする
②Controllerでcontrolとpropsで受け取った項目名を登録してく
③TextFieldをControllerでラップする
以上になります。

export const TextFieldcontrol = ({ name }: { name: string }) => {
  // ①userformContextを用意
  const { control } = useFormContext();
  return (
    <Box mt={4}>
      <Typography>{name}</Typography>
      // ②Controllerでcontrol/name設定
      <Controller
        name={name}
        control={control}
        // ③TextFieldをラップする
        render={({ field }) => <TextField id={name} {...field} />}
      />
    </Box>
  );
};


以上で送信ボタンを押下することで入力した値が取得できる状態になりました。