iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 3
0
自我挑戰組

玩轉 React 從0到1系列 第 15

【Day 15】React 關於事件處理

  • 分享至 

  • xImage
  •  

React 中的事件

在 React 中事件的綁定是直接寫在 JSX 元件上的,並不需要透過 addEventListener 的方式進行監聽,那在寫法上:

  1. 可以直接在 JSX 上添加事件,這裏的命名是使用小駝峰(camelCase)的形式,事實上 React 已經有事先封裝好一些事件類型像是: onClick, onFocus, onMouseMove(可以參考w3c的規範)
  2. 使用 JSX 語法時候需要傳入一個函數作為事件處理函數,而不是一個字串
    (以往是使用onclick="handleClick()",如今使用onClick={this.handleClick})
  3. on*EventType事件類型只能作用在原生的 HTML 標籤上,不能作用在自定義的元件上
  4. 不能通過返回 false 阻止默認行為,必須使用event.preventDefault()

Event(事件)對象

當給 DOM 綁定事件處理函數時,函數會自動傳入一個 event,這個 event 紀錄了當前事件的屬性和方法,在 React 中,雖然 event 不是瀏覽器提供的,但是由 React 將原生瀏覽器的 event 進行封裝,對外提供一個 API,這裡就無須考慮瀏覽器的兼容性,與原生瀏覽器處理事件方法一樣(像是event.preventDefault(), event.stopPropatation),以下為例子:

<a href="#" onClick={this.handleLinkClick}>連結</a>

handleLinkClick(event) {
  event.preventDefault();
  console.log(event);
}

這裏的 event 將回傳:
https://ithelp.ithome.com.tw/upload/images/20201004/20109963RRPXrYpwDA.png

this 綁定

下方的例子在元件建置的時候,雖然沒有寫 constructor 但預設會自動建立並且將 this 綁定進元件裡,所以 在render 後會顯示 handler 的 this 指向 APP,而在在點擊h1時,會顯示 點擊了 以及 handler 的 this 指向 undefined,原因是因為它並沒有將 this 傳給 handleWordClick 這個 function 導致 undefined(詳細原因可以參考 DAY 8)。

import React from 'react';

export default class App extends React.Component {
  handleWordClick() {
    console.log('點擊了');
    console.log('handler 的 this 指向', this);
  }

  render() {
    console.log('handler 的 this 指向', this);

    return (
      <div>
        <h1 onClick={this.handleWordClick}>點擊我</h1>
      </div>
    )
  }
}

那這裏要如何修正?

  1. 在構造函數中綁定
constructor(props) {
  super(props);
  this.handleWordClick = this.handleWordClick.bind(this);
}
  1. JSX 上進行綁定
<h1 onClick={this.handleWordClick.bind(this)}>點擊我</h1>

ps. 但是還是比較建議在 constuctor 進行 this 環境的綁定,而非在 render 時通過 bind方法綁定,因為那會在每次元件渲染的時候都創建一個新的函數,而影響到性能,相反的 contructor 只會執行一次。

向事件處理程序傳遞參數

在操作列表中,有時候為了實現某些操作我們需要額外向事件函數傳遞其他的參數(像是索引),要選取哪一行的ID,那可以透過下面兩種方式向事件函數傳遞參數。

<button onClick={this.handleSelectRow.bind(this.id)}>選取</button>
// 等同於
<button onClick={(e) => this.handleSelectRow(id, e)}>選取</button>

以下例子則是以刪除 list 內部 item,程式如下:
檔案位置,src/listitem.js

import React, { Fragment, Component } from 'react';

export default class ListItem extends Component {
  constructor(props) {
    super(props);
    const { list } = this.props;
    this.state = {
      list,
    }
  }

  handleDelete(index, e) {
    console.log(e);
    // 這裏用拷貝的方式,不建議直接去更動 state
    const list = [...this.state.list];
    list.splice(index, 1);
    this.setState(() => ({list}));
  }

  render() {
    const { list } = this.state;
    return (
      <Fragment>
        <ul>
          {list.map((item, index) =>
            <li
              onClick={(event) => this.handleDelete(index, event)}
              key={index}
            >
              {item}
            </li>
          )}
        </ul>
      </Fragment>
    )
  }
}

檔案位置,src/index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import ListItem from './listitem';

const listData = ['Hello', 'World', 'Test', 'Case'];

ReactDOM.render(
  <ListItem list={listData}  />,
  document.getElementById('root')
);

參考

DOM 的事件傳遞機制:捕獲與冒泡

結論

  • 介紹了 React 中的事件處理

/images/emoticon/emoticon06.gif


上一篇
【Day 14】React 關於 JSX
下一篇
【Day 16】React 元件的生命週期
系列文
玩轉 React 從0到130
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言