/** * Summary of `ReactBrowserEventEmitter` event handling: * * - Top-level delegation is used to trap most native browser events. This * may only occur in the main thread and is the responsibility of * ReactDOMEventListener, which is injected and can therefore support * pluggable event sources. This is the only work that occurs in the main * thread. * * - We normalize and de-duplicate events to account for browser quirks. This * may be done in the worker thread. * * - Forward these native events (with the associated top-level type used to * trap it) to `EventPluginHub`, which in turn will ask plugins if they want * to extract any synthetic events. * * - The `EventPluginHub` will then process each event by annotating them with * "dispatches", a sequence of listeners and IDs that care about that event. * * - The `EventPluginHub` then dispatches the events. * * Overview of React and the event system: * * +------------+ . * | DOM | . * +------------+ . * | . * v . * +------------+ . * | ReactEvent | . * | Listener | . * +------------+ . +-----------+ * | . +--------+|SimpleEvent| * | . | |Plugin | * +-----|------+ . v +-----------+ * | | | . +--------------+ +------------+ * | +-----------.--->|EventPluginHub| | Event | * | | . | | +-----------+ | Propagators| * | ReactEvent | . | | |TapEvent | |------------| * | Emitter | . | |<---+|Plugin | |other plugin| * | | . | | +-----------+ | utilities | * | +-----------.--->| | +------------+ * | | | . +--------------+ * +-----|------+ . ^ +-----------+ * | . | |Enter/Leave| * + . +-------+|Plugin | * +-------------+ . +-----------+ * | application | . * |-------------| . * | | . * | | . * +-------------+ . * . * React Core . General Purpose Event Plugin System */
来一步步的解析,让这货更明朗起来。
Top-level delegation is used to trap most native browser events. This may only occur in the main thread and is the responsibility of ReactDOMEventListener, which is injected and can therefore support pluggable event sources. This is the only work that occurs in the main thread.
Forward these native events (with the associated top-level type used to trap it) to EventPluginHub, which in turn will ask plugins if they want to extract any synthetic events.
functiononClick(event) {console.log(event); // => nullified object.console.log(event.type); // => "click"consteventType=event.type; // => "click"setTimeout(function() {console.log(event.type); // => nullconsole.log(eventType); // => "click" },0);// Won't work. this.state.clickEvent will only contain null values.this.setState({clickEvent: event});// You can still export event properties.this.setState({eventType:event.type});}
The EventPluginHub will then process each event by annotating them with "dispatches", a sequence of listeners and IDs that care about that event.
前面也提到了,每个事件都可以有多个处理程序,即使每个处理程序实际上都被真正的 DOM 侦听一次。因此, 需要累积由事件处理程序及其相应的fiber节点(虚拟 DOM 树中的节点)组成的相关 "调度", 以便后面的使用。
The EventPluginHub then dispatches the events.
插件遍历之前累积的信息并调度事件,从而调用提交的事件处理程序。
本文就说了那么多,但是有几点希望你可以知道:
注册到主DOM (window.document)的顶级事件监听器也可以注册到其他DOM,这取决于应用程序容器的位置。比如,容器被iframe采用,那么iframe的DOM将是主要的事件监听器; 它也可以是一个文档片段、一个shadow DOM 等。重要的是,你应该意识到这一点,并知道事件的传播有这小小的限制。