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;
}
相关推荐
LaughingZhu5 小时前
Product Hunt 每日热榜 | 2026-05-21
前端·人工智能·经验分享·chatgpt·html
怕浪猫5 小时前
Electron 开发实战(一):从零入门核心基础与环境搭建
前端·electron·ai编程
小鹏linux6 小时前
Ubuntu 22.04 部署开源免费具有精美现代web页面的Casdoor账号管理系统
linux·前端·ubuntu·开源·堡垒机
前端若水7 小时前
会话管理:创建、切换、删除对话历史
前端·人工智能·python·react.js
Bigger7 小时前
mini-cc:一个轻量级 AI 编程助手的诞生
前端·ai编程·claude
涵涵(互关)7 小时前
Naive-ui树型选择器只显示根节点
前端·ui·vue
BY组态7 小时前
Ricon组态系统最佳实践:从零开始构建物联网监控平台
前端·物联网·iot·web组态·组态
BY组态7 小时前
Ricon组态系统vs传统组态软件:为什么选择新一代Web组态平台
前端·物联网·iot·web组态·组态
SoaringHeart7 小时前
Flutter进阶:OverlayEntry 插入图层管理器 NOverlayZIndexManager
前端·flutter
放下华子我只抽RuiKe57 小时前
React 从入门到生产(四):自定义 Hook
前端·javascript·人工智能·深度学习·react.js·自然语言处理·前端框架