【React】React Hook Formで再帰的な構造を扱う方法

【React】React Hook Formで再帰的な構造を扱う方法


# TypeScript # React # React Hook Form

この記事でやりたいこと

React Hook Formで再帰的な型って使えないよねー、という話はあるあるらしいのですが、調べてみたところ恐らく内部構造の都合上再帰的な方を適切に扱うことが出来ずIssueにも上がっているようでした。 https://github.com/react-hook-form/react-hook-form/issues/4055

しかし、抜け道は作れるので(やるべきどうかは別の問題として)必要に駆られた時のために残して置こうかと思います。

やり方

型定義と実際の値をずらす

https://wanago.io/2022/05/16/recursive-dynamic-forms-react-hook-form-typescript/ こちらの記事で具体的な実装例が紹介されています。

このコードの肝はFriendsFormField.tsx内で再帰的にFriendsFormFieldが呼ばれている部分で、ここが再帰的なフォームを実現している部分です。

具体的な値の追加や削除の処理はuseFriendsFormField.tsxに記載されていますが、普通にやるとうまく動作しないため出来ないため、下記のように実際の値と型定義に意図的に不整合を生じさせることで無理やり解決しています。

// 実際のデータの(本来指定したい)型
interface FriendsFormValues {
  name: string;
  friends: FriendsFormValues[];
}

// React Hook Formで動作する型
interface FriendsFormValues {
  name: string;
  friends: { name: string }[];
}

friendを追加した際は下記のようなデータ構造(再帰的でない)になるのですが、

{
  "name": "A",
  "friends": [
    {
      "name": "B"
    },
  ],
}

これに対して、下記のようにas friendsとすることでnameだけでなくfriendsが存在するように振る舞わせることが可能になります。

const { fields, append, remove } = useFieldArray({
  control,
  name: "friends[0].friends" as friends,
});

React Hook Form側で初期値として(?)空配列を指定するような処理があるためこのような挙動になっているものと思われます。 そのため、将来のアップデートにより動かなくなる可能性は十分にあるかと思います。

黒魔術感が凄いですね…。