Reactのイベントオブジェクト`e`って何？中身はどうなってるの？

# はじめに

Reactで`onClick`や`onChange`などのイベントハンドラを使うときによく出てくる引数`e`。この`e`は何者で、どんな情報を持っていて、どう使えば良いのでしょうか？

この記事では、イベントオブジェクト（通称`e`）について、**基礎から実用的な活用例まで**をわかりやすく解説します。

# SyntheticEvent `e`とは何か？

`e`は、Reactが発火したDOMイベントに対して自動で渡してくれる、ブラウザのネイティブイベントをラップした「合成イベント（SyntheticEvent）」として処理されます。

これは React が内部的にイベントの挙動を統一し、バグやブラウザ間の差異を減らすための仕組みです。
```javascript
const handleClick = (e) => {
  console.log(e); // SyntheticEvent
};
```

#  代表的な SyntheticEvent の中身

| プロパティ              | 説明                                                    |
| ------------------ | ----------------------------------------------------- |
| `bubbles`          | イベントがバブリング（親に伝播）するかどうか                                |
| `cancelable`       | `preventDefault()` でデフォルト動作をキャンセル可能か                  |
| `clipboardData`    | `copy`, `cut`, `paste` などで使用される `DataTransfer` オブジェクト |
| `currentTarget`    | ハンドラがバインドされた要素。`target`とは異なることがある                     |
| `defaultPrevented` | `preventDefault()` が呼び出されたかどうか                        |
| `eventPhase`       | イベントの伝播フェーズ（1: capturing, 2: target, 3: bubbling）     |
| `target`           | イベントが実際に発生した DOM 要素                                   |
| `timeStamp`        | イベント発生時刻（ページロードからのミリ秒）                                |
| `type`             | イベントタイプ（"click", "copy" など）                           |

# 主要メソッド

| メソッド                     | 説明                                       |
| ------------------------ | ---------------------------------------- |
| `preventDefault()`       | デフォルト動作をキャンセルする（例：フォーム送信）                |
| `stopPropagation()`      | イベントのバブリング（親要素への伝播）を止める                  |
| `isDefaultPrevented()`   | `preventDefault()` が呼ばれたかどうかを返す          |
| `isPropagationStopped()` | `stopPropagation()` が呼ばれたかどうかを返す         |
| `persist()`              | React のイベントプーリングを解除してイベントを永続化する（非同期で使用可） |

# 🖱️ MouseEvent（onClick, onMouseMove など）
| プロパティ     | 型        | 説明             |
| --------- | -------- | -------------- |
| `button`  | `number` | 押されたマウスボタンの番号  |
| `buttons` | `number` | 押されたボタンのビットフラグ |
| `clientX` | `number` | ビューポート左上からのX座標 |
| `clientY` | `number` | ビューポート左上からのY座標 |

# ⌨️ KeyboardEvent（onKeyDown, onKeyUp）
| プロパティ      | 型         | 説明                |
| ---------- | --------- | ----------------- |
| `key`      | `string`  | 押されたキー（例："Enter"） |
| `code`     | `string`  | 物理キー位置（例："KeyA"）  |
| `altKey`   | `boolean` | Altが押されていたか       |
| `ctrlKey`  | `boolean` | Ctrlが押されていたか      |
| `shiftKey` | `boolean` | Shiftが押されていたか     |

# 📋 ClipboardEvent（onCopy, onPaste）
| プロパティ           | 型              | 説明                |
| --------------- | -------------- | ----------------- |
| `clipboardData` | `DataTransfer` | コピー/ペーストされたデータを取得 |

# 実装例：「連打」検出ゲーム

今回は、イベントオブジェクト e.timeStamp を使って、1秒以内に5回クリックできたら勝ち！という連打ゲームを作ってみましょう。

```tsx
import * as React from "react";

export default function RapidFireGame() {
  const [hits, setHits] = React.useState([]);
  const TIME_LIMIT = 1000; // 1秒以内

  const handleClick = (e) => {
    const now = e.timeStamp;
    const updatedHits = [...hits, now].filter(
      (t) => now - t < TIME_LIMIT
    );
    setHits(updatedHits);

    if (updatedHits.length >= 5) {
      alert("💥 Rapid Fire! You win!");
      setHits([]);
    }
  };

  return (
    <div>
      <h2>🔥 Click as fast as you can!</h2>
      <p>Click 5 times within 1 second to win</p>
      <button onClick={handleClick}>Click Me!</button>
      <p>Current streak: {hits.length}</p>
    </div>
  );
}
```

🔎 ポイント

* 今回のクリック時刻（now）を配列に追加
* 配列内のうち「1秒以内のものだけ」に絞り込み
* その結果、今の時点で何回クリックが連続しているかがわかる

# 注意点
:::note warn
注意：非同期で使うなら`e.persist()`が必要な場合も
ReactのSyntheticEventは、パフォーマンス最適化のため**イベントが再利用される**設計になっています。非同期処理で`e`を使いたいときは、`.persist()`を呼びましょう。
:::

ReactのSyntheticEventは、パフォーマンス最適化のため**イベントが再利用される**設計になっています。非同期処理で`e`を使いたいときは、`.persist()`を呼びましょう。

```tsx
const handleChangeAsync = (e) => {
  e.persist(); // これでイベントが解放されなくなる

  setTimeout(() => {
    console.log(e.target.value); // OK
  }, 1000);
};
```

# まとめ

* `e`はReact独自のSyntheticEvent（ラップされたDOMイベント）
* `e.target`を使えば、どのinputで何が入力されたかを取得できる
* `e.preventDefault()`や`e.stopPropagation()`でイベントの振る舞いを制御可能
* `e.persist()`は非同期処理でイベントを安全に使うために必要な場合がある