⚛️

React Hook Formで配列を操作する

2023/02/21に公開
2

はじめに

React で Todo リストに Todo を追加したり、削除したり、ということをラクに実装したい・・・と思うことはありませんか?

大丈夫です!

React Hook Form の useFieldArray フックを使用すれば、カンタンに実現することができます。

useFieldArray フックには配列を操作する仕組みばかりか、要素の追加ボタン、削除ボタン用の関数まで用意されています。

この記事では useFieldArray の基本形をさらりと説明し、応用として useFormContext フックを使用したよりスマートな実装もご紹介します。

バージョン情報

    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-hook-form": "^7.43.1"
➜  workspace git:(feature/issue1) node -v
v16.17.0

基本形

基本形はこちら。
送信ボタンを押下するとコンソールログに配列の内容を出力します。
(※name が空の要素が存在すると、ログ出力しないのでご注意ください。)

https://codesandbox.io/embed/github/YamabikoLab/react-hook-form-sample/tree/develop/?fontsize=14&hidenavigation=1&module=%2Fsrc%2FApp.tsx&theme=dark

配列について

コンポーネントの配列を表示する箇所は下記の通りです。

  • fields:配列
  • index:0 から始まる要素の番号

https://github.com/YamabikoLab/react-hook-form-sample/blob/develop/src/App.tsx#L47-L75

配列の初期値を指定しています。
React Hook Form では基本的に初期値を定義することが推奨されています。
https://github.com/YamabikoLab/react-hook-form-sample/blob/develop/src/App.tsx#L25-L35

ポイント 1

配列コンポーネントなので key を指定する必要があります。
key を指定しない場合、エラーが発生します。

https://github.com/YamabikoLab/react-hook-form-sample/blob/develop/src/App.tsx#L49

ポイント 2

TypseScript の場合は const でキャストする必要があります。

https://github.com/YamabikoLab/react-hook-form-sample/blob/develop/src/App.tsx#L53

削除ボタンについて

削除ボタンは下記のように実装します。
useFieldArray ビルトインの remove と index を指定するだけです。
カンタンですね!

https://github.com/YamabikoLab/react-hook-form-sample/blob/develop/src/App.tsx#L76

追加ボタンについて

追加ボタンは下記のように実装します。
useFieldArray ビルトインの append 関数を使用します。

https://github.com/YamabikoLab/react-hook-form-sample/blob/develop/src/App.tsx#L86-L97

コンポーネント化した配列

基本形の実装では、全てのコンポーネントが App.tsx に実装されていました。
この例では、基本形の実装を下記のようにコンポーネント化します。

https://codesandbox.io/embed/github/YamabikoLab/react-hook-form-sample/tree/feature%2Fissue3/?fontsize=14&hidenavigation=1&module=%2Fsrc%2FApp.tsx&theme=dark

コンポーネント化したため、register や control など useForm のプロパティを受け渡しする必要が出てきます。
パラメータのバケツリレーを解消したいですね。

https://github.com/YamabikoLab/react-hook-form-sample/blob/feature/issue3/src/components/SectionList.tsx#L23-L30

基本形との差分はこちらです
https://github.com/YamabikoLab/react-hook-form-sample/compare/develop...feature/issue3

コンポーネント化した配列(バケツリレー解消タイプ)

useFormContext フックを使用し、パラメータのバケツリレーを解消した実装です。

https://codesandbox.io/embed/github/YamabikoLab/react-hook-form-sample/tree/feature%2Fissue1/?fontsize=14&hidenavigation=1&module=%2Fsrc%2FApp.tsx&theme=dark

下記の通り、バケツリレーが解消されています。
https://github.com/YamabikoLab/react-hook-form-sample/blob/feature/issue1/src/components/SectionList.tsx#L7

バケツリレーとの差分はこちらです。
https://github.com/YamabikoLab/react-hook-form-sample/compare/feature/issue3...feature/issue1

まとめ

はじめは配列コンポーネントの表示や追加ボタン、削除ボタンを独自に実装していました。
しかし、実装してみたところ、配列のインデックス管理が困難であることに気が付きました。

そこで、React で配列操作フレームワークのような仕組みがないか・・・と探したとろころ、「useFieldArray」フックの存在を知りました。

そして、register などのバケツリレーを解消するために useFormContext を導入しました。
その際に行った動作検証環境が、今回ご紹介した codesandbox のソースコードです。

学習段階では TodoList を実装したりして検証していました。
しかし、プロダクトコードを実装する段階になって、追加、削除ボタンを絡めた配列の操作が非常に困難でリスクが伴うことを実感しました。
追加、削除した場合でも配列の状態を壊れることなく維持しつつ、配列のインデックスを開発者が慎重に管理する必要があります。

React Hook Form の「useFieldArray」フックは「配列、追加、削除」の 3 点セットをフレームワークとして提供してくれるため、独自に実装するより安全です。
また、車輪の再発明をしなくて済む、という利点もあるかと思います。

最後に、今回の検証で初めて使用した codesandbox の活用方法についての記事も、いずれ、ご紹介できたらと思っています。

参考資料

https://react-hook-form.com/

https://react-hook-form.com/api/usefieldarray

https://react-hook-form.com/api/useformcontext

https://github.com/YamabikoLab/react-hook-form-sample

Discussion