React 事件收集函数

著有《React 源码》《React 用到的一些算法》《javascript地月星》等多个专栏。欢迎关注。

文章不好写,要是有帮助别忘了点赞,收藏,评论 ~ 你的鼓励 是我继续挖干货的动力🔥。

另外,本文为原创内容,商业转载请联系作者获得授权,非商业转载需注明出处,感谢理解~

事件的收集

这一篇是对React 事件系统的设计原理的补充。在上一篇中只介绍了事件收集的起点,没有介绍事件收集的具体函数。

dispatchEventsForPlugins内还调用了accumulateSinglePhaseListeners负责事件收集, targetFiber就是上一篇介绍过的事件收集的起点ancestorInst

js 复制代码
function accumulateSinglePhaseListeners(targetFiber, reactName, nativeEventType, inCapturePhase, accumulateTargetOnly, nativeEvent) {
  var captureName = reactName !== null ? reactName + 'Capture' : null;
  var reactEventName = inCapturePhase ? captureName : reactName;
  var listeners = [];
  var instance = targetFiber;
  var lastHostComponent = null; 

  while (instance !== null) {//收集Fiber树路径上的所有事件回调函数
    var _instance2 = instance,
        stateNode = _instance2.stateNode,//HostComponents Fiber的真实DOM
        tag = _instance2.tag; // 只要HostComponents (i.e. <div>)

    if (tag === HostComponent && stateNode !== null) {//只要HostComponents
      lastHostComponent = stateNode; // createEventHandle listeners

      if (reactEventName !== null) {
        var listener = getListener(instance, reactEventName); //当前Fiber节点的事件

        if (listener != null) {
          listeners.push(createDispatchListener(instance, listener, lastHostComponent));
        }
      }
    } 
    
    if (accumulateTargetOnly) {
      break;
    } 
    
    // **这就是为什么前面HostPortal到rootA的点击事件也会被收集,因为到HostPortal后还继续向上冒泡**
    instance = instance.return;
  }

  return listeners;
}

在props属性上获取事件:

js 复制代码
function getListener(inst, registrationName) {
  var stateNode = inst.stateNode;

  if (stateNode === null) {
    // Work in progress (ex: onload events in incremental mode).
    return null;
  }
  // 拿到props
  var props = getFiberCurrentPropsFromNode(stateNode);

  if (props === null) {
    // Work in progress.
    return null;
  }
  // 从props中拿到事件。registrationName事件名。
  var listener = props[registrationName];

  if (shouldPreventMouseEvent(registrationName, inst.type, props)) {
    return null;
  }

  if (listener && typeof listener !== 'function') {
    throw new Error("Expected `" + registrationName + "` listener to be a function, instead got a value of `" + typeof listener + "` type.");
  }

  return listener;
}
相关推荐
大圣编程1 小时前
Python中continue语句的用法是什么?
开发语言·前端·python
yuhaiqiang1 小时前
随手 vibecoding 的浏览器插件已经 6000 多次下载,聊聊他的产品设计
前端·后端·面试
之歆2 小时前
Vue商品详情与放大镜组件
前端·javascript·vue.js
再吃一根胡萝卜2 小时前
如何把小米 MiMo 接入 CodeBuddy,打造私有 Agent
前端
负责的蛋挞4 小时前
异步HttpModule的实现方式
java·服务器·前端
YFF菲菲兔4 小时前
其他 Hooks 解析
react.js
丹宇码农6 小时前
把 HLS 字幕玩出花:zwPlayer 如何让 M3U8 视频支持全文搜索、翻译与码率自适应
前端·javascript·音视频·hls·视频播放器
2501_943782356 小时前
【共创季稿事节】猜数字游戏:二分法思维与交互式反馈
前端·游戏·microsoft·harmonyos·鸿蒙·鸿蒙系统
GV191rLvq6 小时前
基于Socket实现的最简单的Web服务器【ASP.NET原理分析】
服务器·前端·asp.net