React Hook Form, MUI, react-number-formatを組み合わせた入力部品を作る

投稿日: April 23, 2022

はじめに

昨今のReactのフォームライブラリではスタンダードになっているReact Hook Form (v7) と、これもReactのプロジェクトではよく用いられるMUI (v5)の各種入力部品を組み合わせて、汎用的に使用できる入力部品を作ってみた。テキストの入力においては純粋なテキスト (string型) の入力と、数値 (number型) の入力を分けたくなるのが常なので、MUIの TextField をベースに、MuiTextFieldMuiNumberField の2つを用意してこれらを区別した。また、数値の入力部品では入力値をフォーマットして表示したい場面も多いので、MuiNumberField にはreact-number-formatも組み込んで、入力値のフォーマットができるようにした。

執筆時の依存バージョン

  • React v18.0.0
  • MUI v5.6.2
  • React Hook Form v7.30.0
  • react-number-format v4.9.1

先に最終的なデモを貼っておく。

GitHubリポジトリは以下。

現状形になっている部品一覧

ここから先はインターフェース設計の思想と、実装時に得られた知見等について書いてみる。

インターフェース

インターフェースの概要

インターフェースを紹介するために、一番シンプルな MuiTextField (string型のテキスト入力部品) を利用するJSX部分のみ紹介する。(実際に動作する完成コードについては冒頭のGitHubリポジトリを参照してもらいたい。) MuiTextField 以外の部品もインターフェイスは同様の設計になっているので、MuiTextField が分かれば他の部品も難なく利用できると思う。

まず、以下のサンプルコードの通り、<MuiTextField> は型引数としてフォームオブジェクトの型を取るようにした。TypeScriptでReact Hook Formを使う場合は必ず定義することになるので、それをそのまま渡せば良い。ここで型を渡すと、name のPropsに渡した文字列がフォームのkeyとして存在するかどうかチェックされる。

Propsは大きく3つに分けられる。

  • React Hook Formで定義されているProps
    今回はこれを入力部品のベースのインターフェースとする
  • MUIの部品に対して定義されているProps
    今回はこれを muiProps としてまとめる
  • 部品の提供者が追加で提供する設定項目のProps
    今回はこれを config としてまとめる
MuiTextFieldの使用例
<MuiTextField<FormData> name='name' control={control} rules={{ required: '必須項目です。', maxLength: { value: 5, message: '5文字以内で入力してください。' } }} config={{ displayErrorMessage: true }} muiProps={{ textFieldProps: { label: '名前', fullWidth: true } }} />

上記で言うと、name, control, rulesはReact Hook Formが公開しているインターフェイスをそのまま適用した箇所である。よって、Propsとしてはネストさせずに渡すことができる。そして、config, muiProps は前述の通り、開発者が独自に提供する設定項目と、MUIのPropsをそれぞれまとめて渡している箇所である。

インターフェースの詳細

とにかくPropsが多いので、3つの大きなまとまりで分けて管理するようにした。一つ目は今回主役となっているReact Hook FormのProps、2つ目はMUIのComponentのProps、3つ目が部品を提供する側が独自で組み込みたいオプションを提供するためのPropsである。

React Hook FormのProps

React Hook Formのインターフェイスは UseControllerProps としてライブラリから提供されている。このPropsはインターフェースとして最表面に出ていて欲しい(ネストして欲しくない)ので、今回作る部品のPropsはこの型との交差型にすることにした。上記のサンプルで言うと、name, control, rulesはReact Hook Formが公開しているインターフェイスで定義されたPropsである。

MUI ComponentのProps

MUIのPropsは部品によっては複数必要になる。例えばAutocompleteではAutocomplete自体のPropsに加えて、内部に持つTextFieldのProps (フォームの幅やラベルなど) も渡せるようにしたい。よって、これらはオブジェクトに整理して、PropsのmuiPropsという口で渡せるようにした。React Hook FormのPropsとMUIのPropsは同名のものが多く衝突する可能性が高い(そして意図せず衝突するとバグる)ので、最初から分けてバグを生む可能性を排除した。

部品提供者が独自に提供する設定項目

提供者が独自で組み込みたいオプションを提供するためのPropsについても、MUIのPropsと同様、オブジェクトにまとめて、configという口で渡せるようにした。react-number-formatのProps (NumberFormatPropsBase) は意味的にはここに収まるのが良いと考えたので、MuiNumberField のconfigについては NumberFormatPropsBase との交差型になっている。


share on...