The under hood of React event —— Synthetic Event

When we attach an event on one JSX element, it's really simple and straight forward: just use camelCase in the tag, like <a href="https://google.com" onClick={clickHandler}>Foo</a>.

However, when you inspect the event trigger in clickHandler, you will find something interesting.

const clickHandler = (event) => {
    event.preventDefault();
    console.log('target', event.target);
    console.log('current target', event.currentTarget);
  };

After clicking, in the browser dev tool console, we can get the correct output:

target   <a href="https://google.com">Foo</a>
current target   <a href="https://google.com">Foo</a>

event.target tells where the event started.

event.currentTarget tells us on which element the event was attached or the element whose eventListener triggered the event.

Then if we print out the event object:

Hmmm, I won't show all properties and functions here. They are too many :P

And we also find the __proto__ of this event is a class:

__proto__: Class
	constructor: f Class()
	__proto__: SyntheticEvent

What's this Synthetic Event ?

According to the official document of React, SyntheticEvent is "a cross-browser wrapper around the browser’s native event" and "has the same interface as the browser’s native event".

That means React encapsulates the browser native event object within this synthetic event and implements all native interfaces, including properties and functions.

Let's do this in clickHandler:

const clickHandler = (event) => {
    event.preventDefault();
    console.log('native target', event.nativEvent.target);
    console.log('native current target', event.nativEvent.currentTarget);
  };

In the console, we have:

native target   <a href="https://google.com">Foo</a>
native current target   #document

Which means, React attaches the native event listener on global document object.

let's have a summary for React event system:

  1. React event is SyntheticEvent, and simulate all abilities of DOM event;
  2. If you need native event, just use event.nativeEvent;
  3. All DOM events are attached on document object.

But why? A couple of reasons:

  1. Better cross-platform performance. E.g. React team just needs to change the implementation layer when moving React from web to mobile, rather than rewrite the whole system;
  2. Attach on document, to reduce memory cost as this will prevent too often untie when components are unmounted;
  3. It's convenient for unified management of events, with this unified entry point.