【React Hook Form】MUIライブラリと素のHTMLの違いをラジオボタンで比較

Reactでフォームを作成するときに便利で優秀なライブラリ、React Hook Form!

素のHTMLで使用するなら導入は簡単ですが、MUI等のUIライブラリと組み合わせると、記述が少し複雑になりますよね。その違いを比較して整理しましたのでご紹介します。

環境

  • react @18.2.0
  • vreact-hook-form @7.41.5
  • typescript @4.9.4
  • mui/material @5.11.4

※全て2023年1月13日時点の最新versionです。

プロジェクト作成・ライブラリインストール

違いを比較するために、プロジェクトの作成とライブラリのインストールをします。

Create React App

% yarn create react-app react-hook-form_radio-button-ts --template typescript
Adding TypeScript | Create React App
Note: this feature is available with react-scripts@2.1.0 and higher.

yarnを使い、typescriptで作成します。

React Hook Form

% yarn add react-hook-form
Get Started
Performant, flexible and extensible forms with easy-to-use validation.

MUI

% yarn add @mui/material @emotion/react @emotion/styled
Installation - Material UI
Install Material UI, the world's most popular React UI framework.

フォームを作成

React Hook Formのドキュメントに、MUIを使ったサンプルとして以下が挙げられていますので、これを使ってフォームを作成してみましょう!

Get Started
Performant, flexible and extensible forms with easy-to-use validation.

MUIのチェックボックス

import { useForm, Controller, SubmitHandler } from "react-hook-form";
import Checkbox from "@mui/material/Checkbox";

interface IFormInputs {
  MyCheckbox: boolean;
}

function App() {
  const { handleSubmit, control } = useForm<IFormInputs>({
    defaultValues: {
      MyCheckbox: false,
    },
  });
  const onSubmit: SubmitHandler<IFormInputs> = (data) => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <Controller
        name="MyCheckbox"
        control={control}
        rules={{ required: true }}
        render={({ field }) => <Checkbox {...field} />}
      />
      <input type="submit" />
    </form>
  );
}

export default App;

サンプルはMaterial UIのバージョンがv4になっていたので、それだけv5に置き換えています。

上記を実行すると以下の画面となります。

チェックを入れ送信をすると、consoleには以下のログが出力されます。

{MyCheckbox: true}

詳細は後述しますので、ここではサラッと目を通すくらいで大丈夫です。

素のHTMLで作ったチェックボックス

上記同様に、チェックボックスをMUIを使わない素のHTMLで記述する方法を見てみましょう。

import { useForm, SubmitHandler } from "react-hook-form";

interface IFormInputs {
  MyCheckbox: boolean;
}

function App() {
  const { handleSubmit, register } = useForm<IFormInputs>({
    defaultValues: {
      MyCheckbox: false,
    },
  });
  const onSubmit: SubmitHandler<IFormInputs> = (data) => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input type="checkbox" {...register("MyCheckbox")} />
      <input type="submit" />
    </form>
  );
}

export default App;

素のHTMLのinputタグで、type=”checkbox”を使った方法だと、一行で書くことができ、MUIと比べシンプルです。

これを実行すると以下の画面となります。

この処理の流れを確認してみましょう!

  1. register関数により、hookにinput要素の内容が登録される
  2. submitボタンが押される
  3. input要素をvalidationする
  4. onSubmitが呼び出される

registerメソッドだけがさすがにわかりにくいので詳しく説明します。

registerとは

公式のドキュメントはこちらになります。

registerメソッドの特徴は以下の2点です。

  • input と select要素で使うことができます。
  • 4つの働きをする。

具体的例をあげます。

<input {...register('firstName')} />

この一行で以下の4つの機能を含んでいます。

<input 
  onChange={onChange} // assign onChange event 
  onBlur={onBlur} // assign onBlur event
  name={name} // assign name prop
  ref={ref} // assign ref prop
/>

これだけの機能を含んでいるのでregisterと記述するだけで、change eventが機能するようになるというわけです。

registerを使った素のHTMLでのシンプルな使い方がわかったところで、MUIを使った方法を改めて見ましょう。

Controller

React Hook FormでMUIを使用するにはControllerを使用する必要があります。

公式ドキュメントがこちらです。

Controllerが必要な理由

import { useForm, Controller, SubmitHandler } from "react-hook-form";
import Checkbox from "@mui/material/Checkbox";

interface IFormInputs {
  MyCheckbox: boolean;
}

function App() {
  const { handleSubmit, control } = useForm<IFormInputs>({
    defaultValues: {
      MyCheckbox: false,
    },
  });
  const onSubmit: SubmitHandler<IFormInputs> = (data) => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <Controller
        name="MyCheckbox"
        control={control}
        rules={{ required: true }}
        render={({ field }) => <Checkbox {...field} />}
      />
      <input type="submit" />
    </form>
  );
}

export default App;

React Hook Formは、uncontrolled componentsを扱います。しかし、MUIはcontrolled componentです。

そのため、React Hook Formでcontrolled componentを扱う場合はControllerを使う必要があるということです。

ここでいうuncontrolled、controlledとは何でしょう?

日本語にすると、非制御コンポーネント制御されたコンポーネントとなり、Reactのドキュメントに記載されています。以下に説明します。

非制御コンポーネントとは(React Hook Form)
  • フォームの実装方法としてReactが推奨している方法
  • フォームのデータの扱いをDOM自身が担う
  • stateの更新を行う場合は、refを使用してDOMからフォームの値を取得する
制御されたコンポーネントとは(MUI)
  •  React コンポーネントが、後続するユーザ入力でフォームで起きることも制御できる状態のことをいう
  • 以下の2つを結合している
    1. <input><textarea><select> のような自身で状態を保持するフォーム要素
    2. setStateで更新されるstate
  • フォームのデータの扱いをReactコンポーネントが担う

React Hook Formは非制御コンポーネントを採用した作りとなっているのですが、MUIは制御されたコンポーネントであるためControllerを使う必要があるというわけです。

Controllerの使い方

上記コードの内、Controllerの中身の以下について詳しく説明します。

      <Controller
        name="MyCheckbox"
        control={control}
        rules={{ required: true }}
        render={({ field }) => <Checkbox {...field} />}
      />
  • name: input要素のユニーク名
  • control: componentを登録するためのメソッドです。Checkboxのコンポーネントを使用しているため、これが必要になります。
  • rules: validationのルールを記載します。
  • render: Reactのメソッドで、Reactの要素を返す関数を受け取り、それを呼び出すことができます。これを使うことで、外部コンポーネントであるMUIとの統合ができています。
    ここで使われているfieldには、「onChange, onBlur, value, name, ref」の5つがあり、子コンポーネントに提供することができます。

番外:React Hook Formをなぜ使うのか

順番が前後してしまっていますが、そもそもReact Hook Formを使う必要があるのか、使うメリットは何なのかを理解しておきたいと思います。

フォームにReact Hook Formを使うメリット

  • バンドル(JavaScriptファイル)サイズが小さくでき、アプリのパフォーマンスを改善できる
  • Reactのイベントシステムを使用していないため、フォーム入力のたびにDOM更新がされることはなく、処理の負荷が少なくなる。
    Reactのイベントシステムを使うと、コンポーネントのライフサイクルに沿って、イベントハンドラーを呼び出し、DOMの更新の管理がされることになる。
  • バリデーションの設定を簡単に行うことができる

まとめ

React Hook FormでのMUIを使う場合は、Controllerメソッドを使用し外部コンポーネントを使用できるようにcontrollerオブジェクトやrender propを用います。

以上、お読みいただきありがとうございました。

コメント