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をコピーしました!

コメント

コメントする


reCaptcha の認証期間が終了しました。ページを再読み込みしてください。

目次