<CodeLearn/>
React レッスン7

イベント処理

クリック、入力、フォーム送信などのイベントを処理しよう

Reactのイベント処理とは?

Reactでは、HTMLのイベント属性と似た方法でイベントを処理しますが、いくつかの違いがあります。

  • イベント名はキャメルケースonClickonChange
  • 文字列ではなく関数を渡す
  • ReactのSyntheticEvent(合成イベント)が使われる
// HTML での書き方
// <button onclick="handleClick()">クリック</button>

// React での書き方
function App() {
  const handleClick = () => {
    alert("クリックされました!");
  };

  return (
    <button onClick={handleClick}>クリック</button>
  );

  // 注意: onClick={handleClick()} と書くと
  // レンダリング時に即座に実行されてしまう!
  // () をつけずに関数自体を渡すこと
}

onClick イベント

最も基本的なクリックイベントのパターンを見てみましょう。

import { useState } from "react";

function ClickExamples() {
  const [count, setCount] = useState(0);
  const [message, setMessage] = useState("");

  // パターン1: 直接関数を渡す
  const handleIncrement = () => {
    setCount(c => c + 1);
  };

  // パターン2: 引数を渡したい場合はアロー関数で包む
  const handleSetMessage = (text) => {
    setMessage(text);
  };

  // パターン3: イベントオブジェクトを使う
  const handleButtonClick = (event) => {
    console.log("クリックされたボタン:", event.target.textContent);
    console.log("座標:", event.clientX, event.clientY);
  };

  return (
    <div>
      <p>カウント: {count}</p>
      {/* パターン1 */}
      <button onClick={handleIncrement}>+1</button>

      {/* パターン2: 引数を渡す */}
      <button onClick={() => handleSetMessage("こんにちは")}>
        挨拶する
      </button>
      <button onClick={() => handleSetMessage("さようなら")}>
        お別れする
      </button>
      <p>{message}</p>

      {/* パターン3: イベントオブジェクト */}
      <button onClick={handleButtonClick}>イベント情報を表示</button>

      {/* インラインで直接書く */}
      <button onClick={() => setCount(0)}>リセット</button>
    </div>
  );
}

onChange イベント(入力の処理)

フォーム入力の変化を検知するのが onChange です。 Reactではフォーム要素を「制御コンポーネント」として扱うのが基本です。

import { useState } from "react";

function FormInputs() {
  const [text, setText] = useState("");
  const [selected, setSelected] = useState("apple");
  const [checked, setChecked] = useState(false);
  const [textarea, setTextarea] = useState("");

  return (
    <div>
      {/* テキスト入力 */}
      <input
        type="text"
        value={text}
        onChange={(e) => setText(e.target.value)}
        placeholder="テキストを入力"
      />
      <p>入力値: {text}({text.length}文字)</p>

      {/* セレクトボックス */}
      <select value={selected} onChange={(e) => setSelected(e.target.value)}>
        <option value="apple">りんご</option>
        <option value="banana">バナナ</option>
        <option value="orange">みかん</option>
      </select>
      <p>選択: {selected}</p>

      {/* チェックボックス */}
      <label>
        <input
          type="checkbox"
          checked={checked}
          onChange={(e) => setChecked(e.target.checked)}
        />
        同意する
      </label>
      <p>チェック: {checked ? "ON" : "OFF"}</p>

      {/* テキストエリア */}
      <textarea
        value={textarea}
        onChange={(e) => setTextarea(e.target.value)}
        rows={3}
        placeholder="自由記述..."
      />
    </div>
  );
}

onSubmit イベント(フォーム送信)

フォーム送信時の処理は onSubmit で行います。preventDefault() でページのリロードを防ぎます。

import { useState } from "react";

function ContactForm() {
  const [formData, setFormData] = useState({
    name: "",
    email: "",
    message: "",
  });
  const [submitted, setSubmitted] = useState(false);

  const handleChange = (e) => {
    const { name, value } = e.target;
    setFormData(prev => ({
      ...prev,
      [name]: value,  // 動的なキーで更新
    }));
  };

  const handleSubmit = (e) => {
    e.preventDefault();  // ページのリロードを防ぐ

    // バリデーション
    if (!formData.name || !formData.email) {
      alert("名前とメールは必須です");
      return;
    }

    console.log("送信データ:", formData);
    setSubmitted(true);

    // フォームをリセット
    setFormData({ name: "", email: "", message: "" });
  };

  if (submitted) {
    return <p>送信完了しました!</p>;
  }

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor="name">名前:</label>
        <input
          id="name"
          name="name"
          value={formData.name}
          onChange={handleChange}
          required
        />
      </div>
      <div>
        <label htmlFor="email">メール:</label>
        <input
          id="email"
          name="email"
          type="email"
          value={formData.email}
          onChange={handleChange}
          required
        />
      </div>
      <div>
        <label htmlFor="message">メッセージ:</label>
        <textarea
          id="message"
          name="message"
          value={formData.message}
          onChange={handleChange}
        />
      </div>
      <button type="submit">送信</button>
    </form>
  );
}

その他のイベント

Reactではさまざまなイベントを扱えます。よく使うものを紹介します。

function VariousEvents() {
  return (
    <div>
      {/* キーボードイベント */}
      <input
        onKeyDown={(e) => {
          if (e.key === "Enter") {
            console.log("Enterが押されました");
          }
        }}
        onKeyUp={(e) => console.log("キーが離された:", e.key)}
        placeholder="キーボードイベント"
      />

      {/* マウスイベント */}
      <div
        onMouseEnter={() => console.log("マウスが入った")}
        onMouseLeave={() => console.log("マウスが出た")}
        onMouseMove={(e) => console.log(e.clientX, e.clientY)}
        style={{ padding: "20px", background: "#f0f0f0" }}
      >
        マウスを乗せてください
      </div>

      {/* フォーカスイベント */}
      <input
        onFocus={() => console.log("フォーカスされた")}
        onBlur={() => console.log("フォーカスが外れた")}
        placeholder="フォーカスイベント"
      />

      {/* スクロールイベント */}
      <div
        onScroll={(e) => {
          console.log("スクロール位置:", e.target.scrollTop);
        }}
        style={{ height: "100px", overflow: "auto" }}
      >
        <div style={{ height: "300px" }}>スクロールしてね</div>
      </div>

      {/* ドラッグ&ドロップ */}
      <div
        draggable
        onDragStart={(e) => console.log("ドラッグ開始")}
        onDragEnd={(e) => console.log("ドラッグ終了")}
      >
        ドラッグしてね
      </div>
    </div>
  );
}

イベントの伝播(バブリング)

イベントは子要素から親要素へと伝播します。これを止めたい場合はstopPropagation() を使います。

function EventPropagation() {
  return (
    <div onClick={() => console.log("親がクリックされた")}>
      <button
        onClick={(e) => {
          e.stopPropagation(); // 親への伝播を止める
          console.log("ボタンがクリックされた");
        }}
      >
        クリック
      </button>
    </div>
  );
}

// preventDefault: ブラウザのデフォルト動作を防ぐ
function PreventExample() {
  return (
    <div>
      {/* リンクの遷移を防ぐ */}
      <a
        href="https://example.com"
        onClick={(e) => {
          e.preventDefault();
          console.log("リンクがクリックされましたが遷移しません");
        }}
      >
        クリックしても遷移しない
      </a>

      {/* フォームの送信を防ぐ */}
      <form onSubmit={(e) => {
        e.preventDefault();
        console.log("フォームの送信をカスタム処理");
      }}>
        <button type="submit">送信</button>
      </form>
    </div>
  );
}

まとめ

  • イベント名はキャメルケース(onClickonChange
  • 関数を渡す(onClick={handleClick})、呼び出さない
  • 引数が必要な場合はアロー関数で包む
  • preventDefault() でデフォルト動作を防ぐ
  • stopPropagation() でイベントの伝播を止める
  • フォームは「制御コンポーネント」パターンで管理する