在弄懂react SyntheticEvent 之前我遇到了一個問題,這個問題一直困擾我很久,知道我看了這篇博客之后,參考了react 文檔,總算弄的大致明白。
首先看一下我的問題。
當我需要在一個點擊事件中應用debounce函數(防抖函數)在防止點擊事件的多次誤觸情況是我的第一反應是這樣的
options.map(item => { let option = ( <li className="uy-menu-item" key={item.fieldName} data-name={item.fieldName} data-type={item.type} onClick={_.debounce(this.handleClick, 200)} > {item.displayName} </li>
); if (item.type === "DIMENSION") { demension.push(option); } else { mersure.push(option); } }); handleClick(e) { let { seriesIndex } = this.state; let key = e.target.getAttribute("data-name”); ... }
這個時候瀏覽器會報出異常:TypeError: Cannot read property 'getAttribute' of null
檢查event對象可以看到target 為null,但是用了debounce 函數之后會出現獲取不到event.target的情況呢?接下來需要介紹下react 的合成事件機制。
合成事件(SyntheticEvent)
事件處理程序通過 合成事件(SyntheticEvent)的實例傳遞,SyntheticEvent 是瀏覽器原生事件跨瀏覽器的封裝。SyntheticEvent 和瀏覽器原生事件一樣有 stopPropagation()、preventDefault() 接口,而且這些接口誇瀏覽器兼容。 如果由於某種原因發現您需要基礎瀏覽器事件,只需使用該nativeEvent屬性即可獲取它。每個SyntheticEvent對象都具有以下屬性:
boolean bubbles boolean cancelable DOMEventTarget currentTarget boolean defaultPrevented number eventPhase boolean isTrusted DOMEvent nativeEvent // 原生事件對象
void preventDefault() boolean isDefaultPrevented() void stopPropagation() boolean isPropagationStopped() DOMEventTarget target number timeStamp string type
事件池
將SyntheticEvent被合並。這意味着SyntheticEvent在調用事件回調之后,將重用該對象並且所有屬性都將無效。這是出於性能原因。因此,您無法以異步方式訪問事件。
function onClick(event) { console.log(event); // => nullified object.
console.log(event.type); // => "click"
const eventType = event.type; // => "click"
setTimeout(function() { console.log(event.type); // => null
console.log(eventType); // => "click"
}, 0); // Won't work. this.state.clickEvent will only contain null values.
this.setState({clickEvent: event}); // You can still export event properties.
this.setState({eventType: event.type}); }
注意:如果要以異步方式訪問事件屬性,則應調用event.persist(),該方法將從池中刪除合成事件,並允許用戶代碼保留對事件的引用。 可以看到react 文檔的注意這里給我我們解決辦法,因為我們在使用debounce函數時,其內部實際上是使用setTimeout異步調用回調函數,所以直接在debounce函數內部獲取外部的event對象是不能直接拿到的,這時調用event.persist()就可以拿到事件的引用。
參考:
在 react 組件中使用 debounce 函數(http://billqiu.github.io/2017/10/15/how-to-debounce-in-react/)
SyntheticEvent(https://reactjs.org/docs/events.html?)