React onClick event vs JS addEventListener
So adding an onClick
event is easy.
class App extends React.Component {
handleClick = () => console.log('Hi there');
render() {
return <button onClick={this.handleClick}>Say something</button>;
}
}
All you need to do is define your event handler function, and attach it to your HTML element inline.
But what about plain ol’ JavaScript event listeners?
document.addEventListener();
Would it be easier, and more beneficial to use that instead of React’s onClick
inline?
Maybe. Let’s start with the basics.
What is a JS Event Listener
According to Mozilla JS docs, an event listener is a function that gets called when a specific event occurs.
Simple example, when a button gets clicked, something happens.
How to add a JS Event Listener
<button id="greetBttn">Click me!</button>
<script>
// Find element
const buttonEl = document.getElementById('greetBttn');
// Add event listener
buttonEl.addEventListener('click', () => alert("Hi user!"));
</script>
Okay, this isn’t too bad. Let’s do a code breakdown.
First I create a variable named buttonEl
, and it’s value is an the button node element.
Then I’m adding an event listener by using, buttonEl.addEventListener()
.
addEventListener(type, handlerFunc);
The addEventListener
function requires 2 arguments. What type of event you’re looking for, and the function to trigger after the event has happened.
You can look for all the event references here.
But like any good samaritan, you must clean up after yourself. You should always remove an event listener when you’re done using it.
How to remove a JS Event Listener
buttonEl.removeEventListener('click', () => alert("Hi user!"));
Just like that! You must use removeEventListener
to clean up.
So far, from the look of using inline onClick
and plain JS event listener, I think I’d rather go with onClick
.
But there are pros to using addEventListener
:
- Works in every browser
- You don’t need React to do this
- You don’t need to import nothing to do this
What is React onClick
onclick
is an inline event. Notice how I didn’t just call it React onclick
.
That’s because this has been thing way before React.
<button onclick="alert('Hi there!');">Greet me!</button>
That code actually works, and events used to be written like that.
React has adopted this same style of attaching events inline, but have added there own touch to it.
All of React events are what they call Synthetic Events.
Quick overview of what is Synthetic Events
Synthetic Events is a React instance that all regular events go through in React.
React has created this to keep consistency for all browsers, and to increase performance since SyntheticEvent
is pooled.
Does React remove event listener?
Yes.
Let’s take a look at plain JS event listener in a React component.
class App extends React.Component {
handleClick = () => {
alert("Hi there");
};
componentDidMount() {
document.getElementById('foo')
.addEventListener('click', this.handleClick)
}
componentWillUnmount() {
document.getElementById('foo')
.removeEventListener('click', this.handleClick)
}
render() {
return <button id="foo">Say something</button>;
}
}
Since I’ve added my own custom event listener, I have to clean it up myself.
But if we do it the React way, they handle that for us!
class App extends React.Component {
handleClick = () => {
alert("Hi there");
};
render() {
return <button onClick={this.handleClick}>Say something</button>;
}
}
And it’s less code. Double win for us!
Which to pick 99% of the time?
Just use React onClick
Synthetic Event.
When to use addEventListener
There are a few a use cases where you need to implement your own event listener.
This is usually because of a specific UI behavior that you or the designers want to achieve.
An example is, when you have a modal popup, and you want to make it disappear when you click anywhere else but the dialog itself.
How to do that?
Here’s the code answer. For the sake of simplicity, I’m going to use inline styling as well.
const styles = {
dialog: {
position: "fixed",
top: 0,
left: 0,
bottom: 0,
right: 0,
margin: "auto",
display: "flex",
alignItems: "center",
justifyContent: "center",
width: 200,
height: 200,
backgroundColor: "#fff",
boxShadow: "0 2px 5px 0 rgba(0,0,0,0.25)"
}
};
class App extends React.Component {
state = {
showDialog: true
};
handleDocumentClick = e => {
// return element object or null
const isClosest = e.target.closest(`[id=foo]`);
if (this.state.showDialog && !isClosest) {
this.setState({ showDialog: false });
}
};
componentDidMount() {
document.addEventListener("click", this.handleDocumentClick);
}
componentWillUnmount() {
document.removeEventListener('click', this.handleDocumentClick);
}
render() {
if (!this.state.showDialog) {
return null;
}
return (
<div id="foo" style={styles.dialog}>
Click outside this box
</div>
);
}
}
Conclusion
Neither approach is bad but, my recommendation is to use React’s onClick Synthetic Event because:
- It handles event pooling
- It handles removing event listeners for you
- It’s better optimize
- It’s more efficient on DOM resolution, and event delegation
This is not to say, never use custom event listeners. Use it only when you can’t do things with regular React events.
I like to tweet about React and post helpful code snippets. Follow me there if you would like some too!