はじめに
前回の記事では、useStateを使ったReactの状態管理について解説しました。本記事では、ユーザーのアクションに応答するための「イベント処理」について詳しく解説します。
Webアプリケーションでは、ボタンのクリック、テキストの入力、フォームの送信など、ユーザーとの対話が不可欠です。Reactでは、これらのインタラクションを「イベントハンドラ」という仕組みで処理します。HTMLのイベント属性とは異なる書き方やルールがあるため、Reactならではの作法を理解することが重要です。
本記事を読むことで、以下のことができるようになります。
- イベントハンドラの基本的な書き方
- onClick、onChange、onSubmitの使い方
- イベントオブジェクトの活用方法
- 制御コンポーネント(Controlled Components)の実装
- 実践的なフォーム処理
実行環境・前提条件
必要な環境
- Node.js 20.x以上
- Viteで作成したReactプロジェクト(TypeScript推奨)
- VS Code(推奨)
前提知識
- 関数コンポーネントの基本
- useStateの使い方
- 基本的なHTML/CSSの知識
Reactのイベント処理の基本
HTMLとReactのイベント処理の違い
HTMLでは、イベント処理を小文字の属性名で記述します。
|
|
Reactでは、キャメルケース(camelCase)で記述し、関数そのものを渡します。
|
|
主な違いをまとめると以下のようになります。
| 項目 | HTML | React |
|---|---|---|
| 属性名 | 小文字(onclick) | キャメルケース(onClick) |
| ハンドラの指定 | 文字列 | 関数 |
| デフォルト動作の防止 | return false | e.preventDefault() |
SyntheticEvent(合成イベント)
Reactでは、ブラウザのネイティブイベントをラップした「SyntheticEvent(合成イベント)」を使用しています。これにより、すべてのブラウザで一貫したイベント処理が可能になります。
|
|
SyntheticEventは、ネイティブイベントと同じインターフェースを持ちますが、ブラウザ間の差異を吸収してくれるため、クロスブラウザ対応を意識する必要がありません。
onClickによるクリックイベント処理
基本的なクリックハンドラ
最もシンプルなクリックイベントの例を見てみましょう。
|
|
期待される結果
ブラウザで確認すると、以下の動作が確認できます。
- 「クリック」ボタンをクリックするたびにカウントが1増加
- 画面上の数値がリアルタイムで更新される
イベントハンドラの書き方3パターン
Reactでは、イベントハンドラを複数の方法で記述できます。
|
|
それぞれの使い分けは以下のとおりです。
| パターン | 適したケース |
|---|---|
| 関数宣言 | 複雑なロジックを含む場合 |
| アロー関数(変数) | コンポーネント内で再利用する場合 |
| インライン | 単純な処理の場合 |
よくある間違い: 関数の即時実行
イベントハンドラを設定する際に、関数を即時実行してしまうミスがよくあります。
|
|
イベントハンドラに引数を渡す
イベントハンドラに追加の引数を渡したい場合は、アロー関数でラップします。
|
|
オンラインで試す
クリックイベントのサンプルは、以下のリンクで実際に試すことができます。
onChangeによる入力イベント処理
テキスト入力の基本
フォーム要素の値を管理するには、useStateとonChangeを組み合わせます。
|
|
期待される結果
ブラウザで確認すると、以下の動作が確認できます。
- 入力フィールドに文字を入力すると、リアルタイムで下の表示が更新される
- 文字数も同時にカウントされる
イベントオブジェクト(e)の中身
onChangeハンドラには、イベントオブジェクトが渡されます。よく使うプロパティを見てみましょう。
|
|
複数の入力フィールドを1つのハンドラで処理
複数の入力フィールドがある場合、name属性を活用して1つのハンドラで処理できます。
|
|
この方法では、[name]: valueという計算されたプロパティ名(Computed Property Names)を使用しています。これにより、どのフィールドが変更されたかをname属性から判断し、対応するstateのプロパティを更新できます。
制御コンポーネントと非制御コンポーネント
制御コンポーネント(Controlled Components)
Reactでフォーム要素を扱う際の推奨パターンが「制御コンポーネント」です。フォーム要素の値をReactのstateで管理し、入力の変更をonChangeで検知してstateを更新します。
|
|
制御コンポーネントのメリットは以下のとおりです。
- 入力値をリアルタイムで検証できる
- 条件に基づいて入力を制限できる
- フォームの値を外部から変更できる
- 複数のフォーム要素間で値を同期できる
非制御コンポーネント(Uncontrolled Components)
非制御コンポーネントでは、フォームの値をDOMが直接管理します。値を取得する際にはrefを使用します。
|
|
| 項目 | 制御コンポーネント | 非制御コンポーネント |
|---|---|---|
| 値の管理 | React state | DOM |
| 値の取得 | stateから直接 | refを使用 |
| リアルタイム検証 | 容易 | 困難 |
| 初期値の設定 | value | defaultValue |
| 推奨度 | 高(通常はこちら) | 特殊なケース向け |
入力値のリアルタイム検証
制御コンポーネントを使えば、入力値のリアルタイム検証が簡単に実装できます。
|
|
onSubmitによるフォーム送信処理
基本的なフォーム送信
フォームの送信を処理するには、formタグにonSubmitハンドラを設定します。
|
|
e.preventDefault()の重要性
HTMLのフォームは、送信時にデフォルトでページをリロードします。Reactではこの動作を防ぐためにe.preventDefault()を呼び出します。
|
|
期待される結果
ブラウザで確認すると、以下の動作が確認できます。
- 入力フィールドに値を入力できる
- 「ログイン」ボタンをクリックすると、ページがリロードされずにデータが処理される
- 送信中は「ログイン中…」と表示され、ボタンが無効化される
さまざまなフォーム要素のイベント処理
チェックボックス
チェックボックスでは、e.target.checkedを使用します。
|
|
ラジオボタン
ラジオボタンは、同じname属性を持つグループ内で1つだけ選択できます。
|
|
セレクトボックス
セレクトボックスも、onChangeで値を管理します。
|
|
テキストエリア
テキストエリアも、inputと同様にvalue/onChangeで制御します。
|
|
イベントの伝播(Event Propagation)
イベントバブリング
Reactのイベントは、DOMと同様に「バブリング」します。子要素で発生したイベントは、親要素にも伝播します。
|
|
ボタンをクリックすると、以下の順序でログが出力されます。
- 「子がクリックされました」
- 「親がクリックされました」
e.stopPropagation()でバブリングを止める
イベントの伝播を止めるには、e.stopPropagation()を使用します。
|
|
e.preventDefault()とe.stopPropagation()の違い
| メソッド | 役割 |
|---|---|
| e.preventDefault() | ブラウザのデフォルト動作を防止(フォーム送信、リンク遷移など) |
| e.stopPropagation() | イベントの親要素への伝播を停止 |
|
|
実践: お問い合わせフォームの実装
これまで学んだ内容を組み合わせて、実践的なお問い合わせフォームを実装してみましょう。
|
|
オンラインで試す
このお問い合わせフォームの動作は、以下のリンクで実際に試すことができます。
よくある間違いとトラブルシューティング
問題1: 入力しても値が変わらない
|
|
制御コンポーネントでは、valueとonChangeは必ずセットで使用します。
問題2: チェックボックスでvalue を使っている
|
|
問題3: イベントハンドラを即時実行している
|
|
問題4: 非同期処理でイベントオブジェクトを使用
|
|
SyntheticEventはパフォーマンスのためにプールされているため、非同期処理内で使用する場合は事前に必要な値を取り出しておく必要があります。
まとめ
本記事では、Reactのイベント処理について基礎から実践まで解説しました。
学んだこと
- イベントハンドラの基本: キャメルケースで記述し、関数を渡す
- onClick: クリックイベントの処理方法
- onChange: フォーム入力の処理とイベントオブジェクトの活用
- onSubmit: フォーム送信とe.preventDefault()の重要性
- 制御コンポーネント: Reactでフォームを扱う推奨パターン
- イベント伝播: バブリングとstopPropagation()
次のステップ
イベント処理の基本を理解したら、次は複数のコンポーネント間で状態を共有する方法を学びましょう。次の記事では、「状態のリフトアップ」について解説します。
また、より複雑なフォーム処理が必要な場合は、React Hook FormやFormikなどのライブラリの導入も検討してみてください。