LoginSignup
0
0

react-hook-formで `FieldPathByValue` とコンポーネント・デリゲーションの組み合わせ

Last updated at Posted at 2024-02-02

デリゲートすることで、ロジックを共有しつつ型を特化させる。

StringFormとNumberFormはそれぞれ文字列型/数値型のフィールドのみしか受け入れない入力フォームのコンポーネントになる。

import {
  Control,
  FieldPathByValue,
  FieldValues,
  PathValue,
  useController,
  useForm,
} from "react-hook-form";

const SubchildForm = <
  T extends FieldValues,
  P extends Path<T>,
  V extends PathValue<T, P>,
>(props: {
  control: Control<T>;
  name: P;
  defaultValue: V;
}) => {
  const { field } = useController({
    control: props.control,
    name: props.name,
    defaultValue: props.defaultValue,
  });

  return <input {...field}>hello</input>;
};

const StringForm = <
  T extends FieldValues,
  P extends FieldPathByValue<T, string | null | undefined>,
  V extends PathValue<T, P>,
>(props: {
  control: Control<T>;
  name: P;
  defaultValue: V;
}) => {
  return (
    <SubchildForm
      control={props.control}
      name={props.name}
      defaultValue={props.defaultValue}
    />
  );
};

const NumberForm = <
  T extends FieldValues,
  P extends FieldPathByValue<T, number | null | undefined>,
  V extends PathValue<T, P>,
>(props: {
  control: Control<T>;
  name: P;
  defaultValue: V;
}) => {
  return (
    <SubchildForm
      control={props.control}
      name={props.name}
      defaultValue={props.defaultValue}
    />
  );
};

type Schema = {
  name: string;
  job?: string | null;
  age: number;
};

const Page = () => {
  const form = useForm<Schema>({
    defaultValues: {
      age: 10,
    },
  });

  return (
    <div>
      <StringForm control={form.control} name="job" defaultValue={""} />
      <NumberForm control={form.control} name="age" defaultValue={0} />
    </div>
  );
};
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0