紀錄工作經驗、相關知識,解決技術相關問題。

Javascript, React, 網站相關, 資訊相關

React 事件處理器 (Event Handlers):常用事件速查表、SyntheticEvent 與傳參寫法

React 事件處理器 (Event Handlers):常用事件速查表、SyntheticEvent 與傳參寫法 特色圖片

在 React 前端開發中,我們會使用不同的 React 事件處理器(Event Handlers)來回應使用者的各種操作行為。與原生 HTML 使用全小寫屬性(例如 onclick)不同,React 的事件屬性一律採用小駝峰命名法(camelCase,例如 onClick、onChange),並直接傳遞 JavaScript 函式作為處理器。本篇整理開發最常使用的事件速查表、合成事件(SyntheticEvent)操作方式,以及綁定事件時的常見注意事項。

一、React 常見事件處理器(Event Handlers)速查表

以下整理 React 元件中最常使用的滑鼠、表單、焦點、鍵盤與捲動事件:

事件屬性名稱觸發時機說明常見前端使用情境
onClick當元素被滑鼠點擊或觸控輕觸時觸發按鈕送出、展開選單、切換狀態、開啟 Modal
onChange當表單輸入元素的值發生變化時即時觸發文字輸入框(input)、下拉選單(select)、核取方塊受控元件同步
onSubmit當表單(form)送出時觸發攔截表單提交並搭配 e.preventDefault() 改由前端發送 API
onFocus當元素獲得焦點時觸發輸入框聚焦時高亮外框樣式、展開搜尋建議清單
onBlur當元素失去焦點時觸發使用者離開輸入框時執行欄位格式驗證(如 Email 格式檢查)
onMouseEnter當滑鼠游標移入元素範圍時觸發(不冒泡)顯示懸停提示框(Tooltip)、切換卡片預覽狀態
onMouseLeave當滑鼠游標離開元素範圍時觸發(不冒泡)隱藏懸停提示框、還原按鈕或卡片預設樣式
onKeyDown / onKeyUp當鍵盤按鍵按下或放開時觸發監聽 Enter 鍵送出訊息、Escape 鍵關閉視窗(註:舊版 onKeyPress 已棄用)
onDragStart / onDrop當拖曳開始、經過(onDragOver)與放下時觸發實作看板卡片拖放排序、檔案拖曳上傳區塊
onScroll當可捲動容器的捲軸位置改變時觸發監聽列表捲動位置、實作無限捲動載入(Infinite Scroll)或回到頂部按鈕

這些事件處理器可以根據元件的互動需求自由組合。接著我們透過實際程式碼範例,說明如何在元件中宣告並綁定事件函式。

二、基本事件綁定與 SyntheticEvent 合成事件物件

在 React 中綁定事件時,會將事件處理函式傳入 JSX 屬性(通常命名為 handle 開頭,例如 handleClick、handleSubmit)。React 會自動傳入一個跨瀏覽器標準化的合成事件物件 e(SyntheticEvent),其介面與原生 DOM 事件一致,支援呼叫 e.preventDefault() 與 e.stopPropagation():

import { useState } from 'react';

export default function LoginForm() {
  const [email, setEmail] = useState('');

  // 處理輸入框文字變更
  const handleEmailChange = (e) => {
    setEmail(e.target.value);
  };

  // 處理表單送出
  const handleFormSubmit = (e) => {
    // 阻止瀏覽器預設的表單換頁重整行為
    e.preventDefault();
    console.log('準備送出的 Email:', email);
  };

  return (
    <form onSubmit={handleFormSubmit}>
      <label htmlFor="user-email">電子信箱:</label>
      <input
        id="user-email"
        type="email"
        value={email}
        onChange={handleEmailChange}
        placeholder="請輸入 Email"
      />
      <button type="submit">登入</button>
    </form>
  );
}

三、如何在事件處理器中傳遞自訂參數?(避免無限迴圈陷阱)

在渲染列表時(例如刪除或編輯特定 id 的項目),我們常需要把 item.id 傳進 onClick 處理函式中。新手最常犯的錯誤是直接在 JSX 寫成 onClick={handleDelete(item.id)},這會導致元件在渲染當下就「立刻呼叫函式」,甚至引發 Too many re-renders 無限迴圈。

正確的做法是使用箭頭函式 () => handleDelete(item.id) 包裹,確保只有在使用者真正點擊時才執行:

export default function TodoList() {
  const todos = [
    { id: 101, title: '整理 API 文件' },
    { id: 102, title: '修正列表 Key 警告' },
  ];

  // 同時接收自訂參數 id 與合成事件物件 e
  const handleDelete = (id, e) => {
    e.stopPropagation(); // 阻止點擊事件向上冒泡觸發父層列點擊
    console.log('準備刪除項目 ID:', id);
  };

  return (
    <ul>
      {todos.map((item) => (
        <li key={item.id}>
          <span>{item.title}</span>
          {/* ✅ 正確寫法:使用箭頭函式延遲至點擊時才呼叫 */}
          <button type="button" onClick={(e) => handleDelete(item.id, e)}>
            刪除
          </button>
        </li>
      ))}
    </ul>
  );
}

💡 列表渲染排錯補充:使用 .map() 搭配事件處理器渲染列表時,若遇到 Console 提示子元件 key 重複的紅字警告,可參考站內另一篇 Encountered Two Children with the Same Key 原因與唯一 Key 解法。

四、React 事件處理的 3 個實務注意事項

  1. 傳遞函式參照而非呼叫結果:無參數時寫 onClick={handleClick},切勿加上小括號寫成 onClick={handleClick()}。
  2. onKeyPress 已正式棄用:若需監聽鍵盤輸入(例如按下 Enter 送出搜尋),請統一使用 onKeyDown 並檢查 if (e.key === 'Enter')。
  3. 事件冒泡與 e.stopPropagation():當卡片外層 div 綁定了點擊導頁 onClick,而卡片內部的「收藏按鈕」也有自己的 onClick 時,記得在內部按鈕的事件函式中呼叫 e.stopPropagation(),避免點擊收藏時連帶觸發外層卡片跳轉。

參考資料與延伸閱讀

發佈留言