Event Handlers decide which actions or behaviors to perform each time an Event is triggered.

In the React application, the event name is written in a small hump format, meaning onclick should be written onclick.

React implements a synthetic event mechanism that brings consistency to React applications and interfaces, while providing high performance benefits. It achieves consistency by standardizing events so that they have the same properties across browsers and platforms.

Composite events are cross-browser wrappers for the browser’s native events. In addition to being compatible with all browsers, it has the same interface as browser native events, including stopPropagation() and preventDefault().

The high performance of synthesized events is achieved by automatically using event brokers. In fact, React does not bind the event handler to the node itself, but rather binds an event listener to the root element of the Document. React maps the event listener to the appropriate component element each time an event is triggered.

Listen for an event

React listening for events is as simple as:

class ShowAlert extends React.Component {
  showAlert() {
    alert("Im an alert");
  }

  render() {
    return <button onClick={this.showAlert}>show alert</button>; }}Copy the code

In the above example, the onClick attribute is our event handler, which is added to the target element to execute the function to be executed when the element is clicked. The onClick property sets the showAlert function.

In simple terms, whenever the button is clicked, the showAlert function is called and displays a message.

Binding approach

In JavaScript, class methods are not bound by default. Therefore, it is important to bind functions to instances of classes.

inrender()In the binding

This is done by calling bind in the render function:

class ChangeInput extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name: ""
    };
  }

  changeText(event) {
    this.setState({
      name: event.target.value
    });
  }

  render() {
    return (
      <div>
        <label htmlFor="name">Enter Text here </label>
        <input type="text"
               id="name"
               onChange={this.changeText.bind(this)} 
        />
        <h3>{this.state.name}</h3>
      </div>); }}Copy the code

In the example above, we use the onChange event handler to listen for keyboard events on the input field, which is done by binding in the Render function. This method needs to be called in the render function. Bind (this).

Why?

Any method in an ES6 class is a normal JavaScript Function and therefore inherits the bind() method from the prototype of Function. Now, when we call onChange inside JSX, this points to our component instance.

Using this approach can cause some potential performance problems because functions are reassigned once after each render. This performance cost may not be noticeable in small React applications, but it is noticeable in larger ones.

inconstructor()In the binding

If binding in render doesn’t work for you, you can also bind in constructor(). Examples are as follows:

class ChangeInput extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name: ""
    };

    this.changeText = this.changeText.bind(this);
  }

  changeText(event) {
    this.setState({
      name: event.target.value
    });
  }

  render() {
    return (
      <div>
        <label htmlFor="name">Enter Text here </label>
        <input type="text" id="name" onChange={this.changeText} />
        <h3>{this.state.name}</h3>
      </div>); }}Copy the code

As you can see, the changeText function is bound to constructor:

this.changeText = this.changeText.bind(this)
Copy the code

The this.changeText on the left of the equals sign points to the changeText method, and since this step is done in Constructor, this points to the ChangeInput component.

The this.changetext on the right of the equals sign points to the same changeText method, but we now call the.bind() method on it.

The this in parentheses refers to the context we passed in.bind(), which points to the ChangeInput component.

It is also worth noting that if changeText is not bound to a component instance, it cannot access this.setState because this would be undefined.

Use the arrow function for binding

Another way to bind event handlers is through arrow functions. With this ES7 class feature (the experimental public Class Fields syntax), we can do event binding at method definition, as shown in the following example:

class ChangeInput extends Component {
  handleEvent = event= > {
    alert("I was clicked");
  };

  render() {
    return (
      <div>
        <button onClick={this.handleEvent}>Click on me</button>
      </div>); }}Copy the code

Arrow function expression syntax is shorter than traditional function expressions and doesn’t have its own this, arguments, super, and new.target.

In the example above, once the component is created, this.HandleEvent does not change. This method is very simple and easy to read.

Like the methods bound in the Render function, this approach has a performance cost.

Use the anonymous arrow function inrenderIn the binding

Define an anonymous function (the arrow function) to bind to the element instead of the event handler directly, so that this is not undefined in the anonymous function:

class LoggingButton extends React.Component {
  handleClick() {
    console.log('this is:'.this);
  }
 
  render() {
    return (
      <button onClick={(e)= > this.handleClick(e)}>
        Click me
      </button>); }}Copy the code

One problem with this approach is that a new callback anonymous function is created each time the LoggingButton is rendered. There is no problem in this example, but passing the value of onClick as props will cause the child component to re-render, so it is not recommended.

Custom components and events

When it comes to events in React, only DOM elements can have event handlers. For example, let’s say we have a component called CustomButton that has an onClick event, but nothing happens when you click on it, for the same reason.

So how do we handle event bindings in custom components?

The answer is that by rendering a DOM element in the CustomButton component and passing onClick as a prop, the CustomButton component really just acts as the delivery medium for the click event.

class CustomButton extends Component {
  render() {
    const { onPress, children } = this.props;

    return (
      <button type="button" onClick={onPress}>
        {children}
      </button>); }}class ChangeInput extends Component {
  handleEvent = (a)= > {
    alert("I was clicked");
  };

  render() {
    return (
      <div>
        <CustomButton onPress={this.handleEvent}>Click on me</CustomButton>
      </div>); }}Copy the code

In this case, the CustomButton component receives a prop called onPress and then passes an onClick to the Button.

Pass parameters to the event handler

It is common to pass extra arguments to an event handler, such as id for a row ID, either way:

<button onClick={(e)=>this.deleteRow(id, e)}>Delete Row</button>

<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
Copy the code

The above two parameter transmission methods are equivalent.

In both cases, the e parameter represents the React event to be passed as the second parameter after the id parameter. The difference is that with the arrow function, the argument e is passed, whereas with bind, the event object and more arguments are passed implicitly.

reference

A guide to React onClick event handlers

The event processing

Correct posture for React event binding