React Hook FormでMaterial UIのText Field
やRadio
を制御するときよりも以下のように考慮する要素が多く、それらが関連しています。そのため、比較的作り込みが必要になります。
- 初期値の設定
- 値の変更
- チェックボックスグループを設置(同じnameでチェックボックスを複数設置)
この記事ではReact Hook FormでMaterial UIのCheckbox
を制御する方法をご紹介します。
制御する要件は以下の通りです。
- 初期値(デフォルトチェック)に対応
- チェックボックスの値の変更を制御
- Material UIを使ってCheckboxグループを設置(同じnameで複数設置)
サンプルコード
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 }
});
https://react-hook-form.com/jp/api
defaultValue/defaultChecked
を使用して input のデフォルト値を設定するか (詳細については React ドキュメントを参照) 、defaultValues
を省略可能な引数として渡してフォーム全体のデフォルト値を設定することができます。
初期値の受け取りは関数内で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のController
のrender
内でチェックボックスを複数作ります。
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のCheckbox
のdefaultChecked
の値を変更すると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を学びたい方にオススメ!
コメント