React はコンポーネントベースで web ページの画面を作れる JavaScript ライブラリです。時として巨大で複雑なページの管理をする必要があります。
しばしば複数のチェックボックスをまとめて管理する必要があります。主にこれは次のような表の操作を作る時です。
これに”全てを選択”、”全ての選択を解除”機能を付け、チェックされているのがどれか state で管理できる様にします。
ちなみに素の JavaScript では次の様にできます。
処理対象のチェックボックス全てをまとめて取得できるセレクタを用意すれば上デモの様に都度、数え上げて cheked の状態を見て処理することで任意の動作をできます。これを React のフックに落とし込むと次の様にできます。
import { useState } from "react";
type useMultipleCheckedRet<T> = {
checked: T[];
toggleChecked: (tgt: T) => void;
allCheck: () => void;
clearCheck: () => void;
};
/**
* 複数チェックの管理用フック
*/
export function useMultipleChecked<T>(
canCheckItems: T[],
initVal?: T[]
): useMultipleCheckedRet<T> {
// チェック済み管理用状態
const [checked, setChecked] = useState<T[]>(initVal || []);
// チェックボックスをクリックした時等のチェック済み、未チェックの入れ替え
const toggleChecked = (tgt: T) => {
if (checked.includes(tgt)) {
setChecked([...checked.filter((item) => item !== tgt)]);
} else {
setChecked([...checked.concat([tgt])]);
}
};
// 全てチェック
const allCheck = () => setChecked(canCheckItems);
// 全てのチェックを解除
const clearCheck = () => setChecked([]);
// 必要な情報と関数のみ外へ
return {
checked,
toggleChecked,
allCheck,
clearCheck
};
}
素の JavaScript で用いていた input 全体をさらうセレクタと checked を見る処理で得ていたチェック済み要素を state に格納します。これで都度クエリセレクタから forEach して……、とせずに済み、すっきりします。実際にこのフックを使ったデモが次です。
import "./styles.css";
import { useMultipleChecked } from "./useMultipleChecked";
const DATA = [{ name: "浜松太郎" }, { name: "浜松次郎" }, { name: "浜松三郎" }];
export default function App() {
const {
checked,
toggleChecked,
allCheck,
clearCheck
} = useMultipleChecked<string>(DATA.map((row) => row.name));
const csvDownload = () => {
alert(checked.join(",") + "のCSVダウンロードを実行");
};
return (
<>
<button className="btn-csv" onClick={csvDownload}>CSVダウンロード</button>
<button className="btn-all" onClick={allCheck}>全てを選択</button>
<button className="btn-rel" onClick={clearCheck}>全ての選択を解除</button>
<table className="search-result-table">
<thead>
<tr>
<th>操作対象</th>
<th>名前</th>
</tr>
</thead>
<tbody>
{DATA.map((row) => (
<tr>
<td>
<input
type="checkbox"
value={row.name}
onChange={() => toggleChecked(row.name)}
checked={checked.includes(row.name)}
/>
</td>
<td>{row.name}</td>
</tr>
))}
</tbody>
</table>
</>
);
}
チェック操作に関するロジックを全てフックに収めたことにより、コンポーネントの中ではチェック操作以外の処理に注力できる様になります。