The introduction

When I was studying React event binding recently, I found that React binding has its own mechanism, which is compositing events. React basically binds events like this

<div className="dome" onClick={this.handleClick}>
Copy the code

A normal event binding would look like this:

<div class="dome" onclick="handleClick()">
Copy the code

React The difference between synthesized events and native events

React synthesizes the event mechanism: Instead of binding the Click event directly to the DOM, React bubbles the event onto the document. React then encapsulates the event into a formal function handler.

React Synthesizes events

If too many event handlers are bound to the DOM, the overall page response and memory footprint can suffer. React implements an intermediate layer, SyntheticEvent, to avoid this kind of DOM event abuse and to mask the underlying event system differences between browsers

  1. React does not bind Click to the DOM when the user adds a function to onClick

  2. Instead, it listens for all supported events at document, and when the event happens and bubbles up to document,React encapsulates the event content into a middle layer called SyntheticEvent.

  3. So when an event is triggered, the function is specified to execute using the uniform dispatch function dispatchEvent

For example

export default class Test extends Component { constructor() { super(arguments); this.onReactClick.bind(this); } componentDidMount() { const parentDom = ReactDOM.findDOMNode(this); const childrenDom = parentDom.querySelector(".button"); childrenDom.addEventListener('click', this.onDomClick, false); } onDomClick() {// Event delegate console.log('Javascript Dom click'); } onReactClick() {// react synthesizes events console.log(' react click'); } render() {return (<div> <button className="button" onClick={this.onreactclick}> </button> </div>)}}Copy the code

It prints this

Javascript Dom click
react-event.jsx:18 
Copy the code

How to use native events in React

React encapsulates almost all native events, but things like:

  • After Modal is enabled, click on other blank areas to turn Modal off
  • Some third-party libraries have been introduced that are implemented as native events and need to interact with each other

Since native events need to be bound to the real DOM, they are typically bound at componentDidMount stage /ref’s function execution stage and unbound at componentWillUnmount stage to avoid memory leaks.

Use a mix of composite events and native events

If a business scenario requires a mix of synthesized and native events, the following points need to be noted:

In response to the order

class Demo extends React.Component {
    componentDidMount() {
        const $this = ReactDOM.findDOMNode(this)
        $this.addEventListener('click', this.onDOMClick, false)
    }

    onDOMClick = evt => {
        console.log('dom event')
    }
    
    onClick = evt => {
        console.log('react event')
    }

    render() {
        return (
            <div onClick={this.onClick}>Demo</div>
        )
    }
}
Copy the code

Let’s examine this: first the DOM event listener is executed, then the event continues to bubble up to the Document, and the composite event listener is executed.

addEventListener

Note: I forgot what the third parameter of addEventListener means. Now let’s review

Event bubbling or event capture

There are two types of event propagation in the HTML DOM, namely bubbling and capturing. Event propagation is a way to define the order of elements when an event occurs.

  • Bubbling: from the inside out
  • Capture: i.e. from the outside in


Using the addEventListener() method, you can specify the propagation type using the useCapture argument, which defaults to false:

  • False: Use bubble propagation
  • True: Use capture propagation

To prevent a bubble

What if evt.stopPropagation() is called in onDOMClick? Since the DOM event is prevented from bubbling and cannot reach the Document, the composite event is naturally not fired

export default class Test extends Component { componentDidMount() { const $parent = ReactDOM.findDOMNode(this); const $child = $parent.querySelector('.child'); $parent.addEventListener('click', this.onParentDOMClick, false) $child.addEventListener('click', this.onChildDOMClick, false) } onParentDOMClick = evt => { console.log('parent dom event') } onChildDOMClick = evt => { console.log('child dom  event') } onParentClick = evt => { console.log('parent react event') } onChildClick = evt => { evt.stopPropagation(); console.log('child react event') } render() { return ( <div onClick={this.onParentClick}> <div className="child" onClick={this.onChildClick}> Demo </div> </div> ) } }Copy the code

The result of calling evt.stoppropagtion () in onChildClick is that React gives itself the isPropagationStopped flag to determine if subsequent listeners are executed.

conclusion

  1. Listeners for synthesized events are uniformly registered on the Document and have only the bubbling phase. So listeners for native events always respond earlier than listeners for synthetic events
  2. Preventing bubbling of native events prevents listeners of synthesized events from executing