React合成事件的原理?
1.React合成事件是什么?
React 合成事件(SyntheticEvent)是 React 模拟原生 DOM 事件所有能力的一个事件对象,即浏览器原生事件的跨浏览器包装器。它根据 W3C 规范 来定义合成事件,兼容所有浏览器,拥有与浏览器原生事件相同的接口。
- 为什么会有合成事件?
将事件绑定在document - v16/容器元素 - v17统一管理,防止很多事件直接绑定在原生的dom元素上。造成一些不可控的情况
React 想实现一个全浏览器的框架, 为了实现这种目标就需要提供全浏览器一致性的事件系统,以此抹平不同浏览器的差异。
- 合成事件与原生事件区别
事件名称命名方式不同
事件处理函数写法不同
阻止默认行为方式不同
// 原生事件命名方式
<button onclick="handleClick()">原生事件命名方式</button>
//React合成事件命名方式
<button onClick={handleClick}>合成事件命名方式 </button>
// 原生事件处理函数写法
<button onclick="handleClick()">原生事件处理函数写法</button>
//React合成事件处理函数写法
<button onClick={handleClick}>React合成事件处理函数写法</button>
```javascript
// 原生事件阻止默认行为方式
<a href="https://www.baidu.com"
onclick="console.log('原生事件阻止默认行为'); return false"
>
原生事件阻止默认行为
</a>
// React合成事件阻止默认行为方式
const handleClick = e => {
e.preventDefault();
console.log('合成事件阻止默认行为');
}
const clickElement = <a href="https://www.baidu.com" onClick={handleClick}>
</a>
- React合成事件与原生事件执行顺序?
• React 所有事件都委托在root 对象上;
• 当真实 DOM 元素触发事件,会冒泡到 root 对象后,再处理 React 事件;
• 在捕获阶段,先注册的先执行,且React合成事件先于原生事件执行;冒泡阶段,先注册的后执行,且原生事件先于React事件执行
- React合成事件实现原理
事件注册,事件触发
React中模拟冒泡和捕获
原理:收集的事件放在dispatchQueue数组中,而冒泡和捕获的区别在于执行时机和顺序,那么我们只需要对数组按照不同顺序循环执行即可
function processDispatchQueueItemsInOrder(
event: ReactSyntheticEvent,
dispatchListeners: Array<DispatchListener>,
inCapturePhase: boolean,
): void {
let previousInstance;
if (inCapturePhase) {
// 事件捕获倒序循环
for (let i = dispatchListeners.length - 1; i >= 0; i--) {
const {instance, currentTarget, listener} = dispatchListeners[i];
if (instance !== previousInstance && event.isPropagationStopped()) {
return;
}
// 执行事件,传入event对象,和currentTarget
executeDispatch(event, listener, currentTarget);
previousInstance = instance;
}
} else {
// 事件冒泡正序循环
for (let i = 0; i < dispatchListeners.length; i++) {
const {instance, currentTarget, listener} = dispatchListeners[i];
// 如果事件对象阻止了冒泡,则return掉循环过程
if (instance !== previousInstance && event.isPropagationStopped()) {
return;
}
executeDispatch(event, listener, currentTarget);
previousInstance = instance;
}
}
}
总结:首先会在fiber节点进入render阶段的complete阶段时,将事件监听绑定在root上。然后调用ensureListeningTo进行事件绑定,生成事件合成对象、收集事件、触发真正的事件。