代码之家  ›  专栏  ›  技术社区  ›  fnune

React何时创建事件?

  •  10
  • fnune  · 技术社区  · 7 年前

    现在,我是这样理解React中的事件处理的:

    1. 本机事件到达目标
    2. 本机事件将备份
    3. document
    4. EventPluginHub
    5. React模拟另一个完整的捕获/气泡往返 SyntheticEvent

    如果我对React内部结构的理解是正确的 this part HTML规范的定义:

    可以开始时,事件对象传播路径必须首先 下定决心。

    是否会等到事件发生时才做出反应 文件 合成事件

    2 回复  |  直到 7 年前
        1
  •  2
  •   Igor Pantović    7 年前

    原因之一是性能。React不是将事件侦听器附加到应用程序内部使用的每个事件,而是为每个事件类型附加一个事件侦听器 document . 然后,当你创建一个, onClick 事件 div ,它只是将其添加到内部事件侦听器映射中。一旦单击div,文档节点上的React侦听器就会找到事件侦听器并用SyntheticEvent调用它。

    这样,react就不必一直从DOM中重新创建和清除侦听器,它只需更改其内部侦听器注册表。

    另一个原因是React的事件冒泡在某些情况下的工作方式与DOM不同。 Portals 特别地。

    举个例子:

    const MyComponent = () => (
      <div onClick={() => console.log('I was clicked!')}>
        MyComponent
        <SomeModalThatUsesPortalComponent>A modal</SomeModalThatUsesPortalComponent>
      </div>
    );
    
    const SomeModalThatUsesPortalComponent = () => {
      return ReactDOM.createPortal(
        <div onClick={() => console.log('Modal clicked!')}>this.props.children</div>,
        document.getElementById('myModalsPortal')
      );
    }
    

    <body>
      <div>
        My Component
      </div>
      <div id="myModalsPortal">
        <div>A modal</div>
      </div>
    </body>
    

    因此,在本例中,当使用门户时,DOM结构与组件结构并不完全匹配。以下是气泡行为的不同之处:

    • 点击 A modal MyComponent's 部门
    • 单击 上的处理程序 MyComponent的 div,因为modal是 MyComponent
        2
  •  1
  •   fnune    7 年前

    React source中没有提到等待事件冒泡以便调度的原因 SyntheticEvent

    很明显,在React-events系统中捕获冒泡事件之前,等待冒泡事件完成冒泡的决定是错误的 只是代码组织的问题

    阅读反应 ReactBrowserEventEmitter listenTo 函数,在此进行简化以使其更易于理解:

    for (let i = 0; i < dependencies.length; i++) {
      const dependency = dependencies[i];
      switch (dependency) {
    
        case: // All event types that do NOT bubble
          trapCapturedEvent(dependency, mountAt);
    
        default:
          // By default, listen on the top level to all non-media events.
          // Media events don't bubble so adding the listener wouldn't do anything.
          const isMediaEvent = mediaEventTypes.indexOf(dependency) !== -1;
          if (!isMediaEvent) {
            trapBubbledEvent(dependency, mountAt);
          }
          break;
    
      }
      isListening[dependency] = true;
    }
    

    区分冒泡事件和不冒泡事件(并保持代码可读性)的最简单方法似乎是在冒泡阶段捕获冒泡事件,而在捕获阶段捕获不冒泡事件。

    因此,总的来说,事件的实际工作方式(与我在这个问题上的初始命题进行类比)如下:

    对于气泡事件:

    1. 发生本机事件捕获阶段
    2. 本机事件将备份
    3. React在文档层用(的抽象版本)捕获它 addEventListener(type, handler, false) // False stands for "catch it in the bubbling phase"
    4. React将其置于 ReactBrowserEventEmitter
    5. React模拟事件的另一个完整捕获/气泡往返
    6. React运行在代码中构建的处理程序

    1. 发生本机事件捕获阶段
    2. addEventListener(type, handler, true) // True stands for "catch it in the capture phase"
    3. 反应浏览器事件发射器
    4. React模拟事件的另一个完整捕获/气泡往返
    5. React运行在代码中构建的处理程序
        3
  •  0
  •   Janakiram Maddanala    5 年前

    React通过在文档上添加所有React事件处理程序来执行顶级委托。所以在捕获和气泡阶段会发生以下情况。

    捕获阶段:

    1. 捕获文档上的事件侦听器(本机DOMEvents)
    2. 在react元素(SyntheticEvents)上捕获事件侦听器
    3. 捕获文档(本机DOMEvents)子级上的事件侦听器

    1. 文档子级上的气泡事件侦听器(本机DOMEvents)
    2. react元素上的气泡事件侦听器(SyntheticEvents)