Heim  >  Artikel  >  Web-Frontend  >  Warum verwendet React synthetische Ereignisse?

Warum verwendet React synthetische Ereignisse?

青灯夜游
青灯夜游Original
2022-07-14 19:19:412909Durchsuche

React verwendet synthetische Ereignisse für drei Hauptzwecke: 1. Um Browserkompatibilität und eine bessere plattformübergreifende Erzielung zu erreichen, können die von React bereitgestellten synthetischen Ereignisse verwendet werden, um die Unterschiede zwischen verschiedenen Browser-Ereignisobjekten auszugleichen und Ereignisse aus verschiedenen zu simulieren und zu synthetisieren Plattformveranstaltung. 2. Vermeiden Sie Garbage Collection; das React-Ereignisobjekt wird nicht freigegeben, sondern in einem Array gespeichert. Wenn das Ereignis ausgelöst wird, wird es aus dem Array entfernt, um eine häufige Erstellung und Zerstörung zu vermeiden (Garbage Collection). 3. Erleichtern Sie ein einheitliches Ereignismanagement und einen Transaktionsmechanismus.

Warum verwendet React synthetische Ereignisse?

Die Betriebsumgebung dieses Tutorials: Windows 7-System, React18-Version, Dell G3-Computer.

1. Was ist ein synthetisches Ereignis?

Das synthetische Ereignis React (SyntheticEvent) ist ein Ereignisobjekt, das alle Funktionen nativer DOM-Ereignisse simuliert, dh ein browserübergreifender Wrapper für native Browserereignisse. Es definiert synthetische Ereignisse gemäß der W3C-Spezifikation, ist mit allen Browsern kompatibel und verfügt über dieselbe Schnittstelle wie browsernative Ereignisse.

In React sind alle Ereignisse synthetisch und keine nativen DOM-Ereignisse, aber DOM-Ereignisse können über die Eigenschaft e.nativeEvent abgerufen werden. Zum Beispiel:

const button = <button>react 按钮</button>
const handleClick = (e) => console.log(e.nativeEvent); //原生事件对象

Wenn Sie neues Wissen erlernen, müssen Sie wissen, warum diese Technologie auftaucht.

Warum verwendet React synthetische Ereignisse? Es hat drei Hauptzwecke:

  • Ermöglichen Sie die Browserkompatibilität und erreichen Sie eine bessere plattformübergreifende Funktion.

    React verwendet einen Ereignis-Proxy-Mechanismus der obersten Ebene, der die Konsistenz der Bubblings gewährleisten kann und browserübergreifend ausgeführt werden kann. Die von React bereitgestellten synthetischen Ereignisse werden verwendet, um die Unterschiede zwischen verschiedenen Browser-Ereignisobjekten auszugleichen und synthetische Ereignisse von verschiedenen Plattformereignissen zu simulieren.

  • Speicherbereinigung vermeiden

    Ereignisobjekte können häufig erstellt und recycelt werden, daher führt React einen Ereignispool ein, um Ereignisobjekte im Ereignispool abzurufen oder freizugeben. Das heißt, das React-Ereignisobjekt wird nicht freigegeben, sondern in einem Array gespeichert. Wenn das Ereignis ausgelöst wird, wird es aus dem Array entfernt, um eine häufige Erstellung und Zerstörung zu vermeiden (Garbage Collection).

  • Bequemer einheitlicher Ereignisverwaltungs- und Transaktionsmechanismus

本文不介绍源码啦,对具体实现的源码有兴趣的朋友可以查阅:《React SyntheticEvent》 。
https://github.com/facebook/react/blob/75ab53b9e1de662121e68dabb010655943d28d11/packages/events/SyntheticEvent.js#L62

2. Native Ereignisüberprüfung

JavaScript-Ereignismodelle sind hauptsächlich in drei Typen unterteilt: ursprüngliches Ereignismodell (DOM0), DOM2-Ereignismodell, IE-Ereignis Modell .

1.DOM0-Ereignismodell

wird auch als ursprüngliches Ereignismodell bezeichnet. In diesem Modell breiten sich Ereignisse nicht aus, das heißt, es gibt kein Konzept für den Ereignisfluss. Die Ereignisbindungs-Abhörfunktion ist relativ einfach, es gibt zwei Möglichkeiten:

//HTML代码种直接绑定:
<button></button>

//通过JS代码指定属性值:
var btn = document.getElementById('.test');
btn.onclick = fun;
//移除监听函数:
btn.onclick = null;

Vorteile: Starke Kompatibilität unterstützt alle Browser

Nachteile: Es gibt keine Trennung zwischen Logik und Anzeige. Es kann nur eine Abhörfunktion für dasselbe Ereignis gebunden werden dasselbe später registrierte Ereignis. Dieses Ereignis überschreibt zuvor registrierte Ereignisse.

2.DOM2-Ereignismodell

Das vom W3C festgelegte Standardmodell. Moderne Browser (Browser außer IE6-8) unterstützen dieses Modell. In diesem Ereignismodell gibt es drei Prozesse für ein Ereignis:

Ereigniserfassungsphase (Erfassungsphase). Das Ereignis breitet sich vom Dokument bis zum Zielelement aus und prüft, ob die übergebenen Knoten an die Ereignisüberwachungsfunktion gebunden sind, und führt diese gegebenenfalls aus.

Ereignisverarbeitungsphase (Zielphase). Wenn das Ereignis das Zielelement erreicht, wird die Abhörfunktion des Zielelements ausgelöst.

Event-Sprudelphase. Das Ereignis sprudelt vom Zielelement zum Dokument und prüft, ob die übergebenen Knoten an die Ereignisüberwachungsfunktion gebunden sind, und führt sie gegebenenfalls aus.

//事件绑定监听函数的方式如下:
addEventListener(eventType, handler, useCapture)

//事件移除监听函数的方式如下:
removeEventListener(eventType, handler, useCapture)

3.IE-Ereignismodell

Das IE-Ereignismodell hat zwei Prozesse:

Ereignisverarbeitungsphase (Zielphase). Wenn das Ereignis das Zielelement erreicht, wird die Abhörfunktion des Zielelements ausgelöst.

Event-Sprudelphase. Das Ereignis sprudelt vom Zielelement zum Dokument und prüft, ob die übergebenen Knoten an die Ereignisüberwachungsfunktion gebunden sind, und führt sie gegebenenfalls aus.

//事件绑定监听函数的方式如下:
attachEvent(eventType, handler)

//事件移除监听函数的方式如下:
detachEvent(eventType, handler)

4. Ereignisfluss

Warum verwendet React synthetische Ereignisse?

Wie in der Abbildung oben gezeigt, umfasst der sogenannte Ereignisfluss drei Phasen: Ereigniserfassung, Zielphase und Ereignissprudeln. Die Ereigniserfassung erfolgt von außen nach innen, entsprechend dem mit dem roten Pfeil markierten Fenster -> html... -> . Das Sprudeln des Ereignisses erfolgt von innen nach außen, entsprechend dem Ziel ... ->

  • Ereigniserfassung

    Wenn ein Element ein Ereignis auslöst (z. B. onclick), sendet das Objektdokument der obersten Ebene einen Ereignisstrom, der zusammen mit den Knoten des DOM-Baums zum Zielelementknoten fließt, bis er erreicht wird der Punkt, an dem das Ereignis tatsächlich auftritt. Während dieses Vorgangs wird die entsprechende Abhörfunktion des Ereignisses nicht ausgelöst.

  • Ereignisziel

    Führen Sie nach Erreichen des Zielelements die entsprechende Verarbeitungsfunktion des Ereignisses des Zielelements aus. Wenn keine Listening-Funktion gebunden ist, wird sie nicht ausgeführt.

  • Event sprudelt

    从目标元素开始,往顶层元素传播。途中如果有节点绑定了相应的事件处理函数,这些函数都会被触发一次。如果想阻止事件起泡,可以使用 e.stopPropagation() 或者 e.cancelBubble=true(IE)来阻止事件的冒泡传播。

  • 事件委托/事件代理

    简单理解就是将一个响应事件委托到另一个元素。 当子节点被点击时,click 事件向上冒泡,父节点捕获到事件后,我们判断是否为所需的节点,然后进行处理。其优点在于减少内存消耗和动态绑定事件。

三、React合成事件原理

React合成事件的工作原理大致可以分为两个阶段:

  • 事件绑定

  • 事件触发

在React17之前,React是把事件委托在document上的,React17及以后版本不再把事件委托在document上,而是委托在挂载的容器上了,本文以16.x版本的React为例来探寻React的合成事件。当真实的dom触发事件时,此时构造React合成事件对象,按照冒泡或者捕获的路径去收集真正的事件处理函数,在此过程中会先处理原生事件,然后当冒泡到document对象后,再处理React事件。举个栗子:

import React from 'react';
import './App.less';

class Test extends React.Component {
  parentRef: React.RefObject<any>;

  childRef: React.RefObject<any>;

  constructor(props) {
    super(props);
    this.parentRef = React.createRef();
    this.childRef = React.createRef();
  }

  componentDidMount() {
    document.addEventListener(
      'click',
      () => {
        console.log(`document原生事件捕获`);
      },
      true,
    );
    document.addEventListener('click', () => {
      console.log(`document原生事件冒泡`);
    });
    this.parentRef.current.addEventListener(
      'click',
      () => {
        console.log(`父元素原生事件捕获`);
      },
      true,
    );
    this.parentRef.current.addEventListener('click', () => {
      console.log(`父元素原生事件冒泡`);
    });
    this.childRef.current.addEventListener(
      'click',
      () => {
        console.log(`子元素原生事件捕获`);
      },
      true,
    );
    this.childRef.current.addEventListener('click', () => {
      console.log(`子元素原生事件冒泡`);
    });
  }

  handleParentBubble = () => {
    console.log(`父元素React事件冒泡`);
  };

  handleChildBubble = () => {
    console.log(`子元素React事件冒泡`);
  };

  handleParentCapture = () => {
    console.log(`父元素React事件捕获`);
  };

  handleChileCapture = () => {
    console.log(`子元素React事件捕获`);
  };

  render() {
    return (
      <p>
        </p>
<p>
          事件处理测试
        </p>
      
    );
  }
}

export default Test;</any></any>

上面案例打印的结果为:

Warum verwendet React synthetische Ereignisse?

注:React17中上述案例的执行会有所区别,会先执行所有捕获事件后,再执行所有冒泡事件。

1、事件绑定

通过上述案例,我们知道了React合成事件和原生事件执行的过程,两者其实是通过一个叫事件插件(EventPlugin)的模块产生关联的,每个插件只处理对应的合成事件,比如onClick事件对应SimpleEventPlugin插件,这样React在一开始会把这些插件加载进来,通过插件初始化一些全局对象,比如其中有一个对象是registrationNameDependencies,它定义了合成事件与原生事件的对应关系如下:

{
    onClick: ['click'],
    onClickCapture: ['click'],
    onChange: ['blur', 'change', 'click', 'focus', 'input', 'keydown', 'keyup', 'selectionchange'],
    ...
}

registrationNameModule对象指定了React事件到对应插件plugin的映射:

{
    onClick: SimpleEventPlugin,
    onClickCapture: SimpleEventPlugin,
    onChange: ChangeEventPlugin,
    ...
}

plugins对象就是上述插件的列表。在某个节点渲染过程中,合成事件比如onClick是作为它的prop的,如果判断该prop为事件类型,根据合成事件类型找到对应依赖的原生事件注册绑定到顶层document上,dispatchEvent为统一的事件处理函数。

2、事件触发

当任意事件触发都会执行dispatchEvent函数,比如上述事例中,当用户点击Child的p时会遍历这个元素的所有父元素,依次对每一级元素进行事件的收集处理,构造合成事件对象(SyntheticEvent–也就是通常我们说的React中自定义函数的默认参数event,原生的事件对象对应它的一个属性),然后由此形成了一条「链」,这条链会将合成事件依次存入eventQueue中,而后会遍历eventQueue模拟一遍捕获和冒泡阶段,然后通过runEventsInBatch方法依次触发调用每一项的监听事件,在此过程中会根据事件类型判断属于冒泡阶段还是捕获阶段触发,比如onClick是在冒泡阶段触发,onClickCapture是在捕获阶段触发,在事件处理完成后进行释放。SyntheticEvent对象属性如下:

boolean bubbles
boolean cancelable
DOMEventTarget currentTarget
boolean defaultPrevented
number eventPhase
boolean isTrusted
DOMEvent nativeEvent // 原生事件对象
void preventDefault()
boolean isDefaultPrevented()
void stopPropagation()
boolean isPropagationStopped()
void persist()
DOMEventTarget target
number timeStamp
string type

dispatchEvent伪代码如下:

dispatchEvent = (event) => {
    const path = []; // 合成事件链
    let current = event.target; // 触发事件源
    while (current) {
      path.push(current);
      current = current.parentNode; // 逐级往上进行收集
    }
    // 模拟捕获和冒泡阶段
    // path = [target, p, body, html, ...]
    for (let i = path.length - 1; i >= 0; i--) {
      const targetHandler = path[i].onClickCapture;
      targetHandler && targetHandler();
    }
    for (let i = 0; i <p><strong>3、更改事件委托(React v17.0)</strong></p><p>自React发布以来, 一直自动进行事件委托。当 document 上触发 DOM 事件时,React 会找出调用的组件,然后 React 事件会在组件中向上 “冒泡”。但实际上,原生事件已经冒泡出了 document 级别,React 在其中安装了事件处理器。</p><p>但是,这就是逐步升级的困难所在。</p><p>在 React 17 中,React 将不再向 document 附加事件处理器。而会将事件处理器附加到渲染 React 树的根 DOM 容器中:</p><pre class="brush:php;toolbar:false">const rootNode = document.getElementById('root');
ReactDOM.render(<app></app>, rootNode);

在 React 16 或更早版本中,React 会对大多数事件执行 document.addEventListener()。React 17 将会在底层调用 rootNode.addEventListener()

Warum verwendet React synthetische Ereignisse?

四、注意

由于事件对象可能会频繁创建和回收在React16.x中,合成事件SyntheticEvent采用了事件池,合成事件会被放进事件池中统一管理,这样能够减少内存开销。React通过合成事件,模拟捕获和冒泡阶段,从而达到不同浏览器兼容的目的。另外,React不建议将原生事件和合成事件一起使用,这样很容易造成使用混乱。

Aufgrund von Änderungen bei der Ereignisdelegierung in Version 17 ist die Verschachtelung alter und neuer React-Bäume jetzt sicherer. Beachten Sie, dass beide Versionen mindestens 17 sein müssen, damit dies funktioniert, weshalb ein Upgrade auf React 17 und höher dringend empfohlen wird.

【Verwandte Empfehlung: Redis-Video-Tutorial

Das obige ist der detaillierte Inhalt vonWarum verwendet React synthetische Ereignisse?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn