ボタン押下時の処理判定はユーティリティか、カスタムフックか
ボタンを押した際に、「処理を実行するか」「スキップするか」を判定する処理をどこに実装するべきか迷うことがあります。
結論としては、Reactに依存するかどうかで判断すると分かりやすくなります。
ユーティリティにする場合
判定処理が引数だけで完結するのであれば、ユーティリティとして実装します。
例
- 入力値のバリデーション
- 選択件数のチェック
- 権限情報を受け取って実行可否を判定
- 処理対象が存在するかのチェック
- ボタン押下時に処理を実行するか、スキップするかの判定
export function shouldExecute(params: ExecuteParams): boolean {
if (params.targets.length === 0) {
return false;
}
if (!params.hasPermission) {
return false;
}
return true;
}
コンポーネントでは、判定結果に応じて処理を実行します。
const handleClick = () => {
if (!shouldExecute(params)) {
return;
}
execute();
};
メリット
- Reactに依存しない
- 単体テストが容易
- 他の画面やバックエンドでも再利用しやすい
- 責務が明確になる
カスタムフックにする場合
判定処理がReactの状態やライフサイクルに依存する場合は、カスタムフックとして実装します。
例
-
useStateでエラー状態を保持する -
useEffectで入力変更を監視する -
useContextからユーザー情報を取得する - ReduxやReact Queryなどの状態を参照する
function useExecutePermission() {
const user = useCurrentUser();
return {
canExecute: user.role === "admin",
};
}
const { canExecute } = useExecutePermission();
const handleClick = () => {
if (!canExecute) {
return;
}
execute();
};
判断基準
| 内容 | ユーティリティ | カスタムフック |
|---|---|---|
| 引数だけで判定できる | ○ | × |
React API(useState、useEffectなど)を使う |
× | ○ |
| React以外でも利用したい | ○ | △ |
| 状態管理を行う | × | ○ |
まとめ
ボタン押下時の「処理を実行するか」「スキップするか」の判定は、引数だけで完結するのであればユーティリティに実装するのが基本です。
一方で、Reactの状態管理やライフサイクルに依存する場合は、カスタムフックとして実装します。
迷ったら、「この処理はReactがなくても動くか?」を基準に判断すると、適切な設計になりやすくなります。