Event handlers
In JavaScript development, we often think of our application as reacting to user events on the page. For instance, we may listen for a submit button on the page to be clicked, and when it is, validate a form. Functions that respond to these user events are sometimes dubbed event handlers or event listeners.
In a simple JavaScript application, we register these event handlers by querying the DOM for some element and adding an event listener function to run when the event of interest occurs. Here is how we might do this:
document.querySelector('form').addEventListener('click', validateForm); function validateForm() { alert('The form is valid!'); }
In the early days of JavaScript, we probably would have used HTML event attributes in order to respond to user events on some element. The equivalent code for this inline approach to event handling might look something like this:
<form onsubmit="validateForm()"> ... </form>
In React, the way we do event handling is more like the inline JavaScript of yesteryear. Elements in React can optionally take event handler properties in order to respond to user inputs. A React element is the portion of a component that is returned from the render function. In other words, it is a description of what we want rendered on the screen, generally written in JSX. Our form from the previous example written in JSX would only have a couple of subtle differences:
<form onSubmit={validateForm}>
To show an example of event handling in context, let's return to our NewsItem
example. Let's imagine that we want our application to respond to a user clicking on the news item. We can do this by creating an event listener function in the component and adding it to the outer element in JSX:
import React, { Component, PropTypes } from 'react';
import Title from './Title';
export default class NewsItem extends Component {
onClick() {
alert(`You've clicked on ${this.props.titleText}`);
}
render() {
return (
<div
className="news-item"
onClick={this.onClick.bind(this)}
>
<Image />
<Title
highlighted
>
{this.props.titleText}
</Title>
<Byline />
<Description />
</div>
);
}
}
NewsItem.propTypes = {
titleText: PropTypes.string.isRequired
};
Take note that we are binding the render
method's this
context to the onClick
method when adding it as a click handler:
onClick={this.onClick.bind(this)}
We need to do this in order to ensure this has the same meaning in the onClick
method as it does in other component methods. This way, we can still access props and call other component methods. However, the better way to bind the this
context to the event handler method is to do so within the component's constructor:
constructor(props) { super(props); this.onClick = this.onClick.bind(this); }
Then there is no need to re-bind the event handler in the JSX, which can be simplified:
<div className="news-item" onClick={this.onClick} >
This method is preferred not only because it reduces the amount of typing, but also because React internally optimizes to make it more efficient.
Event listeners in React, much as they do without React, receive an optional argument that is an object representing the user event. We can access this event object in order to suppress default behavior, for instance, in a form submission, by using event.preventDefault()
. We can also use the event object to, for example, see what document element was targeted by the action or, in the case of a key press event, see which specific key was pressed by the user. To get access to the event, we just need to add it as a parameter to our event listener method:
onClick(event) {
console.log('User event', event);
alert(`You've clicked on${this.props.titleText}`);
}