React Hook FormでMaterial UIのCheckboxを制御

この記事はReact Hook Form v6を用いて Material UI v4のCheckboxを制御した記事です。
React Hook Form v7をお使いの方はReact Hook Form v7でMaterial UI v4のCheckboxを制御を参考にしてください。

React Hook FormでMaterial UIのText FieldRadioを制御するときよりも以下のように考慮する要素が多く、それらが関連しています。そのため、比較的作り込みが必要になります。

  • 初期値の設定
  • 値の変更
  • チェックボックスグループを設置(同じnameでチェックボックスを複数設置)

この記事ではReact Hook FormでMaterial UIのCheckboxを制御する方法をご紹介します。
制御する要件は以下の通りです。

  • 初期値(デフォルトチェック)に対応
  • チェックボックスの値の変更を制御
  • Material UIを使ってCheckboxグループを設置(同じnameで複数設置)
目次

サンプルコード

この記事はReact Hook Form v6を用いて Material UI v4のCheckboxを制御した記事です。
React Hook Form v7をお使いの方はReact Hook Form v7でMaterial UI v4のCheckboxを制御を参考にしてください。


import React from "react";
import { useForm, Controller } from "react-hook-form";
import FormControlLabel from "@material-ui/core/FormControlLabel";
import Checkbox from "@material-ui/core/Checkbox";
import { FormHelperText, FormControl } from "@material-ui/core";

const items = [
  {
    id: 0,
    name: "Object 0"
  },
  {
    id: 1,
    name: "Object 1"
  },
  {
    id: 2,
    name: "Object 2"
  },
  {
    id: 3,
    name: "Object 3"
  },
  {
    id: 4,
    name: "Object 4"
  }
];

export default function CheckboxesGroup() {
  const defaultIds = [1, 3];

  const { control, handleSubmit, getValues, errors } = useForm({
    defaultValues: { item_ids: defaultIds }
  });

  const handleCheck = checkedId => {
    const { item_ids: ids } = getValues();
    const newIds = ids?.includes(checkedId)
      ? ids?.filter(id => id !== checkedId)
      : [...(ids ?? []), checkedId];
    return newIds;
  };

  return (
    <form onSubmit={handleSubmit(data => console.log("data", data.item_ids))}>
      ...
      <FormControl error={!!errors.item_ids?.message}>
        <FormHelperText>{errors.item_ids?.message}</FormHelperText>
        <Controller
          name="item_ids"
          render={props =>
            items.map((item, index) => (
              <FormControlLabel
                control={
                  <Checkbox
                    onChange={() => props.onChange(handleCheck(item.id))}
                    defaultChecked={defaultIds.includes(item.id)}
                  />
                }
                key={item.id}
                label={item.name}
              />
            ))
          }
          control={control}
        />
      </FormControl>
      ...
    </form>
  );
}

https://codesandbox.io/s/material-demo-bzj4i?file=/demo.js

要件を満たす制御の解説

React Hook FormでMaterial UIのCheckboxを制御する要件は以下の通りでした。

  • 初期値に対応
  • チェックボックスの値の変更を制御
  • Material UIを使ってCheckboxグループを設置(同じnameで複数設置)

この要件を満たすコードの解説をします。

初期値に対応

React Hook Formで制御しているフォームに初期値を設定するにはuseForm()defaultValuesを設定する必要があります。

 const { control, handleSubmit, getValues, errors } = useForm({
    defaultValues: { item_ids: defaultIds }
  });

defaultValue/defaultChecked を使用して input のデフォルト値を設定するか (詳細については React ドキュメントを参照) 、defaultValues を省略可能な引数として渡してフォーム全体のデフォルト値を設定することができます。

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

初期値の受け取りは関数内でgetValues()を使用したり、Controller内のvalueで初期値を受け取れます。

https://react-hook-form.com/jp/api/#getValues

チェックボックスの値の変更を制御

チェックボックスに変更があった場合、handleCheck関数が実行されます。

handleCheck関数内では

  • 変更があったアイテムIDがすでに値にあれば削除
  • 変更があったアイテムIDがすでに値になければ値に追加

をしています。

const handleCheck = checkedId => {
  const { item_ids: ids } = getValues();
  const newIds = ids?.includes(checkedId)
      ? ids?.filter(id => id !== checkedId)
      : [...(ids ?? []), checkedId];
  return newIds;
};

Material UIのCheckboxグループを設置

Material UIのCheckboxを複数設置する場合はReact Hook FormのControllerrender内でチェックボックスを複数作ります。

React Hook FormのControllerごと複数生成しないように気をつけてください。

<Controller
  name="item_ids"
  render={props =>
    items.map((item, index) => (
      <FormControlLabel
        control={
          <Checkbox
            onChange={() => props.onChange(handleCheck(item.id))}
            defaultChecked={defaultIds.includes(item.id)}
          />
        }
        key={item.id}
        label={item.name}
      />
    ))
  }
  control={control}
/>

また、Material UIのCheckboxで値の変更があったとき、Material UIのCheckboxdefaultCheckedの値を変更するとCheckboxでエラーが出ます。

なので、defaultIdsは

  • チェックボックスのデフォルトの値の変数はconstにしておく
  • チェックボックスのデフォルトの値と変更した値は別で持つ

にすることによって、defaultCheckedの値を変更できなくしてエラーが出ないようにしています。

const defaultIds = [1, 3];

参考

https://github.com/react-hook-form/react-hook-form/blob/master/app/src/controller.tsx

https://github.com/react-hook-form/react-hook-form/issues/1517

下記に参考書をまとめておきます。

りーほー
りーほー

JavaScriptを基礎からしっかり学びたい方におすすめ!

りーほー
りーほー

JavaScriptを基礎から応用までガッツリ学びたい方におすすめ!

りーほー
りーほー

Reactの概念や仕組みを把握し、開発で使えるReactを学びたい方にオススメ!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

エンジニアを目指す方必見!おすすめプログラミングスクール

最短でエンジニアになるには、いかに効率よく学習するかが重要です。モチベーションを維持しながら最短でエンジニアを目指すならプログラミングスクールを利用するのもおすすめです。

コメント

コメントする

目次