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
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)
}
}
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>
)
- 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)
}
}
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)
Hey, This is such an amazing explanation for the Synthetic Events, Thank you :)
This was the best explanation to React's SyntheticEvent that I could find! Thank you :-)
oh, thanks Maricris it means a lot to me 😍
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?
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
Event will nullified when you try to access it asynchronously. in above example, it should be wrapped in setTimeOut or promise.
good one
This was so easy!! I came on this article after 2 articles and react official documentation, thank you!!
Thank you.
In the first solution to the problem, event should be null once I invoked the handler, should't it?
Do u mean that the handler will not be executed till the event get nullifed?!
I liked your way of writing 💜 ..
Thanks for sharing
Thaaaank you😍,
Hope it helps
Great article 👍
That's was very helpful for me