接著來學習在React當中處理事件,主要會提到React當中的事件傳遞機制,內容如下:
在原生JavaScript中,事件傳遞有兩個階段:事件捕獲和事件冒泡。事件捕獲是自頂向下的,而事件冒泡是自底向上的。而在React中,使用的是合成事件系統(Synthetic Event System),並且在React元素樹中,事件從最內層的元素冒泡到最外層的元素。
export default function Toolbar() {
return (
<div className="Toolbar" onClick={() => {
alert('You clicked on the toolbar!');
}}>
<button onClick={() => alert('Playing!')}>
Play Movie
</button>
<button onClick={() => alert('Uploading!')}>
Upload Image
</button>
</div>
);
}
譬如,在這個Toolbar 當中,有二個按鈕,當點擊了任一其中一個按鈕「 Play Movie」或是「Upload Image」時,首先會先接收到該按鈕(事件本身)的通知「Playing!」或是「Uploading!」,再來還會接收到另一個通知也就是父容器的「You clicked on the toolbar!」,顯示到也點擊到Toolbar 本身。這也就是React預設的事件傳遞邏輯。
但也許我們不需要二次的通知,可以怎麼做呢?
function Button({ onClick, children }) {
return (
<button onClick={e => {
e.stopPropagation();
onClick();
}}>
{children}
</button>
);
}
export default function Toolbar() {
return (
<div className="Toolbar" onClick={() => {
alert('You clicked on the toolbar!');
}}>
<Button onClick={() => alert('Playing!')}>
Play Movie
</Button>
<Button onClick={() => alert('Uploading!')}>
Upload Image
</Button>
</div>
);
}
我們可以透過event object 來停止事件的傳遞,在button 元素的onClick 當中呼叫 e.stopPropagation() 即可讓事件傳遞停留在子元件,而不會讓父元件也跳出一次通知了。
讓我們再一次看看這邊發生了什麼事:
[User Clicks Button] #使用者點擊按鈕
↓
[React calls onClick handler passed to <button>] #React 呼叫onClick事件處理器並傳遞到<button>
↓
[Button onClick Handler]
- Calls e.stopPropagation() # 阻止事件進一步傳播
- Calls onClick function (prop) # 呼叫從Toolbar傳遞過來的onClick函數
↓
[Toolbar onClick Function]
- Displays the button's own alert # 顯示按鈕自己的警告框
↓
[Parent <div> onClick Handler (Not Executed)]
- Since propagation was stopped, this handler does not run # 由於事件傳播被阻止,這個處理器不執行
雖然React當中事件傳遞的預設是冒泡,有其他方法能夠操作捕獲嗎?
我們可以透過追加捕獲的設定來達到這個目標
<div onClickCapture={() => { /* this runs first */ }}>
<button onClick={e => e.stopPropagation()} />
<button onClick={e => e.stopPropagation()} />
</div>
我們可以透過 e.preventDefault() 來預防瀏覽器的預設行為,譬如,在button存在於form當中時,每當點擊整個頁面的預設行為為reload,透過追加e.preventDefault() 可以防止這樣的reload。
export default function Signup() {
return (
<form onSubmit={e => {
e.preventDefault();
alert('Submitting!');
}}>
<input />
<button>Send</button>
</form>
);
}
這二者容易混淆,需要多加留意
在 React 中,事件處理被封裝成合成事件(Synthetic Events)。合成事件是 React 提供的一個抽象層,用於處理跨不同瀏覽器的事件處理。React 的合成事件系統在背後處理了各種瀏覽器差異,以確保事件處理在各種環境中保持一致。
合成事件的一些特點和好處包括:
<div>
或 <body>
),而不是每個元素都附加一個事件處理程序。這可以減少內存使用和提高性能。