@click在 Vue 專案中,可以使用 @click 監聽點擊事件:
<button
type="button"
class="delete-btn"
@click="emit('delete', todo.id)"
>
刪除
</button>
@click 是 v-on:click 的縮寫。當使用者點擊按鈕時,就會執行後面的程式碼。
到了 React 專案,同一個刪除按鈕則寫成:
<button
type="button"
className="delete-btn"
onClick={() => onDelete(todo.id)}
>
刪除
</button>
Vue 的 @click 在 React JSX 中對應的是 onClick。React 內建元素的事件處理 Prop 使用駝峰式命名,因此第二個單字的開頭要大寫。除了 onClick,目前專案中還有 onChange、onSubmit,分別用來處理資料改變與表單送出。
React 會將事件處理函式傳給 JSX 元素,而不是立即執行它:
<button onClick={handleClick}>
點我
</button>
這裡是把 handleClick 這個函式本身交給 onClick,等使用者真的點擊按鈕時,React 才會呼叫它。
React 官方文件:回應事件
這是 React 事件處理中很重要的一個觀念:要把函式傳給事件,而不是在 Render 時就把它執行掉。
寫成 onClick={handleClick},代表把函式本身交出去,React 會等到點擊發生時才執行它
但如果寫成 onClick={handleClick()},這個函式會在 Component Render 的當下就立刻執行,而不是等使用者點擊
雖然乍看之下只差在有沒有加後面那個 () 但感覺就是初學者很容易會去踩到的坑R!
目前刪除按鈕不是直接寫成 onClick={onDelete},而是:
onClick={() => onDelete(todo.id)}
因為刪除 Todo 時,需要把目前這筆資料的 id 傳給 onDelete。如果直接寫成 onClick={onDelete(todo.id)},onDelete() 一樣會在 Render 時立即執行;用箭頭函式把它包起來,就能延後到使用者點擊後才執行,並且把 id 帶進去。
切換完成狀態時也是同樣的邏輯:
onChange={() => onToggle(todo.id)}
這部分我自己先簡單記成:不需要參數時直接傳函式本身;需要在事件發生時才帶入參數,就用箭頭函式包一層。
事件處理函式也可以接收到一個事件物件,裡面包含這次事件的相關資訊。目前 TodoForm.tsx 的輸入框是這樣寫的:
onChange={(event) => setText(event.target.value)}
這裡的 event 就是事件物件,透過 event.target.value 可以取得輸入框目前的文字,再交給 setText() 更新 State。事件物件不一定要叫 event,也常會簡寫成 e,兩者作用相同,只是變數名稱不同而已。
Vue 的表單會寫成 @submit.prevent="handleSubmit",.prevent 會阻止表單送出時重新整理整個頁面。React 沒有這種事件修飾符,而是要在事件處理函式裡自己呼叫 event.preventDefault():
function handleSubmit(event: FormEvent<HTMLFormElement>) {
event.preventDefault()
const trimmed = text.trim()
if (trimmed === '') return
onAdd(trimmed)
setText('')
}
整個流程是:
使用者送出表單 → React 呼叫 handleSubmit → event.preventDefault() 先擋下瀏覽器預設的重新整理行為 → 再繼續往下執行新增待辦事項、清空輸入框。
Vue 是把這個功能寫在 Template 的 .prevent 修飾符上,React 則是直接呼叫 JavaScript 原生的 preventDefault(),說起來更貼近瀏覽器原本的事件機制。
onClick 跟 onDelete,兩者是同一種東西嗎?目前專案中同時出現 onClick 和 onDelete,看起來很像,但性質不一樣。click 是瀏覽器提供的點擊事件,而 onClick 是 React JSX 內建元素支援的事件處理 Prop;onDelete 則是開發者自己命名的 Prop。App 將 deleteTodo 這個函式透過 Props 傳給 TodoList,再傳給 TodoItem,最後才在按鈕被點擊時呼叫。onDelete 只是採用了以 on 開頭的命名習慣,並不代表 React 內建了這個事件。
Vue Component 可以透過 emit() 發出自訂事件,讓外層使用 @delete 監聽;React Component 則常把事件處理函式當成 Props 傳入,子層需要通知外層時就直接呼叫這個函式。兩者都是為了讓子層 Component 通知外層發生了什麼事,只是採用的方式不同。
onClick、onChange、onSubmit 等駝峰式命名的事件名稱,取代 Vue 的 @click 等寫法event.target.value 能取得輸入框目前的值event.preventDefault() 可以阻止瀏覽器的預設行為,對應 Vue 的 .prevent 修飾符click 是瀏覽器事件,onClick 是 React 內建元素的事件處理 Prop;onDelete 則是自行命名、透過 Props 傳遞的函式emit() 處理事件;React 則很直接地把事件處理也交回 JavaScript 函式。React 的部分大致上預計到下一篇會先告一段落,從下下篇開始會進入 TypeScript 篇章,探索並認識 TypeScript 。
下篇見!