写给进阶玩家的 React 事件系统原理

news/2024/7/19 14:29:53 标签: js, javascript, nokia, framework, gwt
js_content">

【 简介 】

React 合成事件是 React 模拟原生 DOM 事件所有能力的一个对象,它根据 W3C规范来定义合成事件,兼容所有浏览器拥有与浏览器原生事件相同的接口。

react官方描述分别打印出合成事件对象e和原生对象e.nativeEvent

【 React 事件系统架构 】

image.png

_【 核心代码 】// _我们可以将react系统分成注册和执行两部分去理解:

一、注册:

// 
function enqueuePutListener(inst, registrationName, listener, transaction) {
    ...
  var isDocumentFragment = containerInfo._node && containerInfo._node.nodeType === DOC_FRAGMENT_TYPE;
  1. 找到document
  var doc = isDocumentFragment ? containerInfo._node : containerInfo._ownerDocument;
  2. 注册事件,将事件注册到document上
  3. listenTo(registrationName, doc);
  存储事件,放入事务队列中
}

react事件系统内部对事件在不同浏览器上的执行做了兼容因此无需使用者考虑浏览器相关情况:

  listen: function listen(target, eventType, callback) {
    if (target.addEventListener) {
      将原生事件添加到target这个dom上,也就是上边传递的document上
      这就是只有document这个DOM节点上有原生事件的原因
      target.addEventListener(eventType, callback, false);
      ...
    } else if (target.attachEvent) {
      target.attachEvent('on' + eventType, callback);
      ...
    }
  }

二、执行:

事件分发dispatchEvent(react合成事件的冒泡机制)

function handleTopLevelImpl(bookKeeping) {
  1. 找到事件触发的DOM和React Component
  var nativeEventTarget = getEventTarget(bookKeeping.nativeEvent);
  var targetInst = ReactDOMComponentTree.getClosestInstanceFromNode(nativeEventTarget);

  2. 执行事件回调前,先由当前组件向上遍历它的所有父组件。
  得到ancestors这个数组,这个数组同时也是冒泡顺序。
  var ancestor = targetInst;
  do {
    bookKeeping.ancestors.push(ancestor);
    ancestor = ancestor && findParent(ancestor);
  } while (ancestor);

  这个顺序就是冒泡的顺序,并且我们发现不能通过stopPropagation来阻止'冒泡'。
  for (var i = 0; i < bookKeeping.ancestors.length; i++) {
    targetInst = bookKeeping.ancestors[i];
    ReactEventListener._handleTopLevel(bookKeeping.topLevelType, targetInst, bookKeeping.nativeEvent, getEventTarget(bookKeeping.nativeEvent));
  }
}

handleTopLevel 构造合成事件并执行(依赖EventPluginHub)

1. 初始化时将eventPlugin注册到EventPluginHub中,不同plugin分别构造不同类型的合成事件
  ReactInjection.EventPluginHub.injectEventPluginsByName({
    ...不同插件
  });
  
2. 将事件放入事件池:
   EventPluginHub.enqueueEvents(events);
3. 再处理队列中的事件,包括之前未处理完的:
   EventPluginHub.processEventQueue(false);

【 合成事件、原生事件混用demo】

刚接触react的同学,往往在react事件使用时会与原生事件混合(这里并非指责这种混用行为,只是在混用阶段需要区分出react时间系统和js本身事件的执行差异),时常会有事件执行出现不符合预期的情况,这里我们用一个小demo来感受下二者执行的差异:打印出执行结果:

image.png

由此我们可以了解到如下原生事件、react事件、document上挂载事件执行顺序:

image.png

【 合成事件存在意义 】

1.统一管理(document)

react事件集中在document上集中管理

2.不同浏览器兼容问题

3.减少事件创建销毁的性能损耗(避免频繁的垃圾回收机制)

react事件队列的存储和取出使用缓解了dom元素注册销毁所消耗的性能

4.利用合成事件的冒泡从document中触发的特性

【 合成事件中存在的问题 】

1.原生事件和合成事件混用时原生事件对入react合成事件的影响

  • 原生事件中禁止冒泡会阻止react合成事件的执行

  • react合成事件禁止冒泡不会对原生生效

2.事件池中中事件处理函数全部被调用之后,所有属性都会被置为 null

避免方法:
  • e.persist() //可以阻止事件池清掉取出事件

  • 17版本react会有废弃事件池等更改,此现象也不会存在

3.不同版本的 React 组件嵌套使用时,e.stopPropagation无法正常工作(两个不同版本的事件系统是独立的,都注册到document时的时间不相同)

【 相关参考 】

  • https://react.docschina.org/

  • https://github.com/facebook/react/[1]

  • React 17 要来了,非常特别的一版 - 梦烬 - 博客园[2]

参考资料

[1]

https://github.com/facebook/react/: https://github.com/facebook/react/

[2]

React 17 要来了,非常特别的一版 - 梦烬 - 博客园: https://www.cnblogs.com/ayqy/p/react-17.html

❤️ 谢谢支持

以上便是本次分享的全部内容,希望对你有所帮助^_^

喜欢的话别忘了 分享、点赞、收藏 三连哦~。


http://www.niftyadmin.cn/n/1251256.html

相关文章

继承WebMvcConfigurationSupport后自动配置不生效的问题及如何配置拦截器

网上有很多文章说从spring boot2.0之后在构造spring配置文件时建议推荐直接实现WebMvcConfigurer或者直接继承WebMvcConfigurationSupport &#xff0c;经测试实现WebMvcConfigurer是没问题&#xff0c;但继承WebMvcConfigurationSupport类是会导致自动配置失效的。 一、继承We…

征途手游2新开区服务器维护多久,征途2手游新区开服表 征途2手游新区开服时间详解[图]...

征途2手游在今天4月12日正式全平台上线了&#xff0c;玩的也人也很多&#xff0c;什么时候能发开新区呢&#xff1f;下面是友情MT为大家带来的征途2手游新区开服表&#xff0c;征途2手游新区开服时间详解&#xff0c;希望能帮助到大家&#xff01;征途2手游新区开服表征途2手游…

一篇文章带你了解 Vite 2项目工程化

Vite2 自2月17号发布之后&#xff0c;收获了前端圈的一片哀嚎&#xff1a;学不动了……不不不&#xff0c;你得学&#xff01;不仅是因为Vite2新的插件结构&#xff0c;丝滑的开发体验以及和Vue3的完美结合&#xff0c;而且面试的话面试官肯定都会提一嘴&#xff0c;如果你还没…

S3快速入门

文档&#xff1a; https://s3browser.com/help.aspx 获取&#xff1a;AWS Access Keys . https://s3browser.com/aws-access-key-id-and-secret-access-key.aspx

实现无感刷新token我是这样做的

原文: https://juejin.cn/post/6983582201690456071前言 最近在做需求的时候,涉及到登录token,产品提出一个问题:能不能让token过期时间长一点&#xff0c;我频繁的要去登录。前端&#xff1a;后端&#xff0c;你能不能把token 过期时间设置的长一点。后端&#xff1a;可以,但是…

S3常用功能(amazon)

一 .Amazon S3介绍 Amazon Simple Storage Service (Amazon S3) 是一种对象存储&#xff0c;它具有简单的 Web 服务接口&#xff0c;可用于在 Web 上的任何位置存储和检索任意数量的数据。它能够提供 99.999999999% 的持久性&#xff0c;并且可以在全球大规模传递数万亿对象。…

分享少数人才了解的 VSCode 写代码效率更高的技巧

vscode 是我们写代码常用的编辑器&#xff0c;它的功能很多&#xff0c;但其实我们有很多功能都没用到&#xff0c;这篇文章就是想梳理下那些可能你不知道的但是却对效率提高很有帮助的一些技巧。包括&#xff1a;一键执行 npm scripts一键 diff、预览在新页面搜索git 视图显示…

js正则

1.正确表达式 "^\\d$"  //非负整数&#xff08;正整数 0&#xff09; "^[0-9]*[1-9][0-9]*$"  //正整数 "^((-\\d)|(0))$"  //非正整数&#xff08;负整数 0&#xff09; "^-[0-9]*[1-9][0-9]*$"  //负整数 "^-?\\d$&…