DEV Community

Cover image for React synthetic events
nagwan sami for Smiley Code

Posted on • Updated on

React synthetic events

I would like a fresh start 😇

React
A JavaScript library used to build vivid shiny user interfaces🥰.

Event
The different ways the user uses to interact with an application, e.g. click, mouseover, input… etc

Synthetic
It is a ...🤔 Let's understand how React deals with events first.

React listens to every event at the document level, after receiving an event from the browser, React wraps this event with a wrapper that has the same interface as the native browser event, which means we still can use methods like preventDefault().

So what is the need for this wrapper?!!😏

think of a situation where the exact same event has different names across different browsers.

imagine an event that fires when the user winks😉, this event in chrome called A in Safari called B, in such case, we will need to make different implementations for each browser😵.

What this wrapper does is registering all the different names for the same event effect, winking in our case, with only one name, so in a case when we want to listen to our winking effect instead of being listening to A for chrome and B for Safari we just use onWink, which is the wrapper react creates around the real event.

So whenever we are triggering an event in a React component, we are not actually dealing with the real DOM event, instead, we are dealing with React's custom event type, a synthetic event.

Now close your eyes😴, but not this kind of closing😅, and in your memory remember all the onClick(s), onBlur(s), onChange(s) you have ever used in your react components, these are not the real ones, these are react's synthetic events😇.

So we do not have to think anymore about different browsers implementations, react makes creating cross-browsers applications much less painful, which means we can concentrate more on adding browsers prefixes to our CSS properties😅.

This is not the end, as this is not the only bright side of React's synthetic events😃. Another catchy benefit of synthetic events is that React reuses these events objects, by pooling them, which results in performance gains.

Once the event handler is invoked, an event handler is a method executed once an event is triggered, all the properties on this event object will be nullified, set to their empty/default states, to be ready to be reused again.

Till this point, everything looks amazing, and you might feel🧐, but you might also go through some 🤨, 🙄, or even 😤 moments once you see Warning: This synthetic event is reused for performance reasons in the browser.

What makes most of us go through 🤨, 🙄, and 😤 moments, is not that despite it is warning it is written in red, but it is actually accessing any event properties in the event handler function fails

Imagine the following:

import React, { useState } from "react"

const ExampleComponent = (() => {
  const [counter, setCounter] = useState()

  function handelArrowBtn(event) {
    if (event.keyCode === 40) { //down arrow button
      setCounter(counter - 1)
    } else if (event.keyCode === 38) { // up arrow button
      setCounter(counter + 1)
    }
  }

  return (
    <div>
      <input
        type="number"
        value={counter}
        onKeyDown={handelArrowBtn}
       />
    </div>
  )
})

export default ExampleComponent
Enter fullscreen mode Exit fullscreen mode

This counter will neither be increased nor decreased. And our lovely red warning will be printed in the browser console.

Let's see what is happening here...

After the event handler function, handelArrowBtn() in our case, is invoked the object of our synthetic event, onKeyDown in our case, gets nullified, the old values to the keys within this object are no longer exist, the event object returned to its original state to be ready to be reused, and as this is an object, so our handelArrowBtn() has access to it by reference which means our function now has access to the event object with its original state(nullified version).

So, how can we solve this?!😯

Actually, this can be solved in many ways:

  • Store the event property we need
function handelArrowBtn(event) {
  let keyCode = event.keyCode
  if (keyCode === 40) {
    setCounter(counter - 1)
  } else if (keyCode === 38) {
    setCounter(counter + 1)
  }
}
Enter fullscreen mode Exit fullscreen mode

or we may also pass the properties we want as arguments to the event handler function instead of directly accessing it from the function

return (
    <div>
      <input
        type="number"
        value={counter}
        onKeyDown={(e) => handelArrowBtn(e.keyCode)}
      />
    </div>
  )
Enter fullscreen mode Exit fullscreen mode
  • Using event.persist() which will remove the synthetic event from the pool, which enables us accessing the event object properties in our code
function handelArrowBtn(event) {
   event.persist()
   if (event.keyCode === 40) { 
      setCount(count - 1)
    } else if (event.keyCode === 38) {
      setCount(count + 1)
    }
  }
Enter fullscreen mode Exit fullscreen mode

Hope this helps and thanks for reading. If you have any questions or topics you want me to write about I will be happy to help❤️.

Top comments (18)

Collapse
 
ahmdtalat profile image
Ahmd Talat

Hey, This is such an amazing explanation for the Synthetic Events, Thank you :)

Collapse
 
seemcat profile image
Maricris Bonzo

This was the best explanation to React's SyntheticEvent that I could find! Thank you :-)

Collapse
 
nagwan profile image
nagwan sami

oh, thanks Maricris it means a lot to me 😍

Collapse
 
hamidh2 profile image
Hamid Hassani • Edited

You said the properties of the event object will reset but you didn't say anything when this will happen?

I didn't understand this statement: 'our handelArrowBtn() is called asynchronously
after the event object has been nullified '
I didn't get the point of how a simple and synchronous method should be called asynchronously here?

Collapse
 
nagwan profile image
nagwan sami

Hi Hamid, sorry for the late reply,
this happens once the event handler is invoked.
and for the asynchronous part, it was related to another example removed to keep the article light, thanks for the note

Collapse
 
striker2909 profile image
StrikEr2909

Event will nullified when you try to access it asynchronously. in above example, it should be wrapped in setTimeOut or promise.

Collapse
 
saikrishnabanda5 profile image
saikrishnabanda5

good one

Collapse
 
shalinabhargava profile image
Shalina Bhargava

This was so easy!! I came on this article after 2 articles and react official documentation, thank you!!

Collapse
 
junnuravikumar profile image
Junnu

Thank you.

Collapse
 
loaideveloper profile image
Loai-developer

In the first solution to the problem, event should be null once I invoked the handler, should't it?

Collapse
 
nagwan profile image
nagwan sami

Do u mean that the handler will not be executed till the event get nullifed?!

Collapse
 
a_m_h_gad profile image
Jad

I liked your way of writing 💜 ..
Thanks for sharing

Collapse
 
nagwan profile image
nagwan sami

Thaaaank you😍,
Hope it helps

Collapse
 
kemoshousha309 profile image
Kareem Shousha

Great article 👍
That's was very helpful for me