Why should React implement its own event system?
A: In order to be compatible with the differences of event processing among browsers/
Bubbling and trapping
- Bubbling: the event starts from the innermost element and propagates upward until the document object.
- Capture: events start from the outermost layer to the most specific element.
- addEventListener(event, function,useCapture): useCapture=true, the event capture phase calls the processing function; useCapture=false, the event bubbling stage calls the processing function;
In react, if you want to execute in the Capture phase, you can add the Capture suffix to the event.
<div> <button onClick={handleClick} onClickCapture={ handleClickCapture } >click</button> </div>
- Prevent bubbling: e.stopPropagation();
- Block default behavior
Native events: e.preventDefault() and return false;
react event: e.preventDefault()
The event bound to the element in react is not a real event handler, so return false cannot be used to block the default behavior.
How React simulates preventing event bubbling
function runEventsInBatch(){ const dispatchListeners = event._dispatchListeners; if (Array.isArray(dispatchListeners)) { for (let i = 0; i < dispatchListeners.length; i++) { if (event.isPropagationStopped()) { /* Determine whether event bubbling has been prevented */ break; } dispatchListeners[i](event) /* Execute the real handler and handleClick1 */ } } }
Event synthesis
- React events are not bound to elements, but are uniformly bound to the top container.
- The event bound to the element is not a native event, but a react composite event. For example, onClick is bound to click events, and onChange events are composed of blue, change, focus and other events.
Is the event handler function bound to document the handleClick written above?
A: Events bound to document are handled uniformly by dispatchEvent in React. As long as the React event triggers, the first execution is the dispatchEvent.
const listener = dispatchEvent.bind(null,'click',eventSystemFlags,document) /* TODO: Important, here is the real event binding.*/ document.addEventListener('click',listener,false)
Event trigger process
What is the trigger sequence of the following code?
export default function Index(){ const handleClick1 = () => console.log(1) const handleClick2 = () => console.log(2) const handleClick3 = () => console.log(3) const handleClick4 = () => console.log(4) return <div onClick={ handleClick3 } onClickCapture={ handleClick4 } > <button onClick={ handleClick1 } onClickCapture={ handleClick2 } >click</button> </div> }
- The dispatchEvent execution will pass in the real event source button element itself, followed by batch update.
export function batchedEventUpdates(fn,a){ isBatchingEventUpdates = true; //Turn on the batch update switch try{ fn(a) // The event is executed here }finally{ isBatchingEventUpdates = false //Turn off the batch update switch } }
- Find the corresponding processing plug-in SimpleEventPlugin through onClick to synthesize a new event source e.
- Form an event execution queue:
3.1 if the capture phase event onClickCapture is encountered, unshift will be placed in front of the array. This simulates the event capture phase.
3.2 if the event onClick in the bubbling phase is encountered, it will be push ed behind the array to simulate the event bubbling phase.
3.3 collect all the way to the top app to form an execution queue. - Execute the functions of the queue in turn.
Click the button once as above, and the execution sequence of the four events is as follows:
- The first time the event source is found on the button.
- handleClick1 bubble event push processing, handleClick2 capture event unshift processing. Form structure [handleClick2, handleClick1].
- Then look up the event source and encounter div.
- Handleclick3 bubble event push processing, handleclick4 capture event unshift processing. [handleClick4, handleClick2 , handleClick1, handleClick3 ]
- Execute the events in the array in turn, so print 4 2 1 3.