React Hook FormでMaterial UIのCheckboxを制御

React
スポンサーリンク
language

この記事は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>
  );
}
Material demo - CodeSandbox

要件を満たす制御の解説

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で初期値を受け取れます。

API ドキュメント
Performant, flexible and extensible forms with easy-to-use validation.

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

チェックボックスに変更があった場合、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];

参考

react-hook-form/react-hook-form
📋 React Hooks for forms validation (Web + React Native) - react-hook-form/react-hook-form
Material UI + multiple checkboxes + default selected · Issue #1517 · react-hook-form/react-hook-form
I am trying to build a form which accommodates multiple 'grouped' checkboxes using Material UI. The checkboxes are created async from a HTTP Request. I ...

この記事でわからないコードなどがあれば、書籍で勉強するのがおすすめです。
プログラミングの技術の移り変わりは早いので最新版の書籍を購入することをお勧めします。
中古本を買って勉強したけど、今は使われない技術だったということはよくあります。

javascript・Reactでおすすめの書籍をご紹介します。

りーほー
りーほー

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

りーほー
りーほー

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

りーほー
りーほー

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

タイトルとURLをコピーしました