第 8 章:事件處理 (Handling Events)

在前面的章節中,我們已經簡單地使用了一些事件處理,例如按鈕的 onClick 事件。在這一章中,我們將深入學習 React 中的事件系統,了解如何有效地處理使用者互動,以及如何在不同場景下編寫優雅的事件處理程式碼。

8.1 React 事件系統概述

React 實現了自己的事件系統,稱為「合成事件」(SyntheticEvents)。這個系統提供了跨瀏覽器的一致性,並且與原生 DOM 事件保持相容性。

8.1.1 合成事件 (SyntheticEvents)

什麼是合成事件?

合成事件是 React 對原生 DOM 事件的包裝,它具有以下特點:

  • 跨瀏覽器相容性:在所有瀏覽器中提供一致的行為
  • 與原生事件相同的介面:具有與原生事件相同的方法和屬性
  • 效能優化:React 使用事件委託來處理事件,提高效能
  • 預設行為控制:可以使用 preventDefault()stopPropagation()

基本語法:

function Button() {
  const handleClick = (event) => {
    console.log('按鈕被點擊了!');
    console.log('事件型別:', event.type);
    console.log('目標元素:', event.target);
  };

  return <button onClick={handleClick}>點擊我</button>;
}

8.2 常見的事件類型

8.2.1 滑鼠事件

import React, { useState } from 'react';

function MouseEvents() {
  const [message, setMessage] = useState('');
  const [position, setPosition] = useState({ x: 0, y: 0 });

  const handleClick = (e) => {
    setMessage(`按鈕在 (${e.clientX}, ${e.clientY}) 被點擊`);
  };

  const handleDoubleClick = () => {
    setMessage('按鈕被雙擊了!');
  };

  const handleMouseEnter = () => {
    setMessage('滑鼠進入按鈕區域');
  };

  const handleMouseLeave = () => {
    setMessage('滑鼠離開按鈕區域');
  };

  const handleMouseMove = (e) => {
    setPosition({ x: e.clientX, y: e.clientY });
  };

  const handleContextMenu = (e) => {
    e.preventDefault(); // 阻止預設的右鍵選單
    setMessage('右鍵被點擊!');
  };

  return (
    <div>
      <h3>滑鼠事件範例</h3>
      <button
        onClick={handleClick}
        onDoubleClick={handleDoubleClick}
        onMouseEnter={handleMouseEnter}
        onMouseLeave={handleMouseLeave}
        onContextMenu={handleContextMenu}
        style={{
          padding: '10px 20px',
          margin: '10px',
          backgroundColor: '#4CAF50',
          color: 'white',
          border: 'none',
          borderRadius: '4px',
          cursor: 'pointer'
        }}
      >
        互動按鈕
      </button>

      <div 
        onMouseMove={handleMouseMove}
        style={{
          width: '300px',
          height: '200px',
          border: '2px dashed #ccc',
          margin: '10px',
          padding: '10px'
        }}
      >
        <p>在這個區域移動滑鼠</p>
        <p>滑鼠位置: ({position.x}, {position.y})</p>
      </div>

      <p>訊息: {message}</p>
    </div>
  );
}

export default MouseEvents;

8.2.2 鍵盤事件

import React, { useState } from 'react';

function KeyboardEvents() {
  const [inputValue, setInputValue] = useState('');
  const [keyInfo, setKeyInfo] = useState('');
  const [items, setItems] = useState([]);

  const handleKeyDown = (e) => {
    setKeyInfo(`按下: ${e.key} (代碼: ${e.keyCode})`);

    // 處理特殊按鍵
    if (e.key === 'Enter') {
      e.preventDefault();
      if (inputValue.trim()) {
        setItems([...items, inputValue.trim()]);
        setInputValue('');
      }
    } else if (e.key === 'Escape') {
      setInputValue('');
      setKeyInfo('輸入已清除');
    }
  };

  const handleKeyUp = (e) => {
    if (e.key !== 'Enter' && e.key !== 'Escape') {
      setKeyInfo(`放開: ${e.key}`);
    }
  };

  const handleChange = (e) => {
    setInputValue(e.target.value);
  };

  return (
    <div>
      <h3>鍵盤事件範例</h3>
      <div>
        <input
          type="text"
          value={inputValue}
          onChange={handleChange}
          onKeyDown={handleKeyDown}
          onKeyUp={handleKeyUp}
          placeholder="輸入文字,按 Enter 添加項目,Esc 清除"
          style={{
            padding: '8px',
            width: '300px',
            marginBottom: '10px'
          }}
        />
        <p>鍵盤資訊: {keyInfo}</p>
      </div>

      <div>
        <h4>項目列表:</h4>
        <ul>
          {items.map((item, index) => (
            <li key={index}>{item}</li>
          ))}
        </ul>
      </div>
    </div>
  );
}

export default KeyboardEvents;

8.3 事件處理的最佳實踐

8.3.1 事件處理函式的定義方式

1. 在元件內部定義:

function Component() {
  const handleClick = () => {
    console.log('按鈕被點擊');
  };

  return <button onClick={handleClick}>點擊</button>;
}

2. 使用 useCallback 優化:

import React, { useCallback, useState } from 'react';

function OptimizedComponent({ onDataChange }) {
  const [count, setCount] = useState(0);

  // 使用 useCallback 來避免不必要的重新渲染
  const handleIncrement = useCallback(() => {
    setCount(prev => prev + 1);
  }, []);

  const handleDataSubmit = useCallback((data) => {
    onDataChange(data);
  }, [onDataChange]);

  return (
    <div>
      <p>計數: {count}</p>
      <button onClick={handleIncrement}>增加</button>
    </div>
  );
}

8.4 總結

事件處理是 React 應用程式中使用者互動的核心機制。

本章重點:

  • 合成事件系統:React 提供跨瀏覽器相容的事件處理
  • 常見事件類型:滑鼠、鍵盤、表單事件的處理方法
  • 最佳實踐:使用 useCallback、正確傳遞參數、防抖節流
  • 效能優化:事件委託和其他優化技術

關鍵要點:

  1. 使用合成事件:利用 React 的事件系統獲得一致性和效能
  2. 正確處理表單:使用 preventDefault() 控制預設行為
  3. 優化事件處理函式:使用 useCallback 避免不必要的重新渲染
  4. 處理頻繁事件:使用防抖和節流技術

掌握事件處理對於建立互動性強的 React 應用程式至關重要。在下一章中,我們將學習條件渲染和列表渲染,進一步增強我們對 React 渲染機制的理解。

results matching ""

    No results matching ""