React Event Handling

React element event handling is similar to DOM elements. However, there are some syntactic differences:

  • React event binding attribute names use camelCase, not lowercase.
  • With JSX syntax, you need to pass a function as the event handler, rather than a string (the DOM element approach).

The usual HTML approach is:

<button onclick="activateLasers()">
  激活按钮
</button>

In React, the approach is:

<button onClick={activateLasers}>
  激活按钮
</button>

Another difference in React is that you cannot use returnfalseto prevent default behavior; you must explicitly usepreventDefault。

For example, in HTML we usually prevent a link from opening a new page by default like this:
<a href="../index.html" onclick="console.log('点击链接'); return false">
  点我
</a>

In React, the approach is:

function ActionLink() { function handleClick(e) { e.preventDefault(); console.log('Link clicked'); } return ( <a href="#" onClick={handleClick}> Click me </a> ); }

In the example, e is a synthetic event.

When using React, you usually don't need to use addEventListener to add a listener to a DOM element after it is created. You only need to provide a listener when the element is initially rendered.

When you define a component using ES6 class syntax, the event handler becomes a method of the class. For example, the Toggle component below renders a button that lets users toggle the switch state:

Example

class Toggle extends React.Component { constructor(props) { super(props); this.state = {isToggleOn: true}; //This binding is necessary so that `this` can be used in the callback function this.handleClick = this.handleClick.bind(this); } handleClick() { this.setState(prevState => ({ isToggleOn: !prevState.isToggleOn })); } render() { return ( <button onClick={this.handleClick}> {this.state.isToggleOn ? 'ON' : 'OFF'} </button> ); } } const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <Toggle />, document.getElementById('example') );

Try it »

You must be cautious about this in JSX callbacks. Class methods are not bound to this by default. If you forget to bind this.handleClick and pass it to onClick, the value of this will be undefined when you call the function.

In general, if you don't add () after a method, for exampleonClick={this.handleClick}, you should bind this to that method.

If using bind bothers you, there are two ways to solve this. If you are using the experimental property initializer syntax, you can use property initializers to correctly bind callbacks:

class LoggingButton extends React.Component { //This syntax ensures that `this` is bound within handleClick //This is just a test handleClick = () => { console.log('this is:', this); } render() { return ( <button onClick={this.handleClick}> Click me </button> ); } }

If you are not using the property initializer syntax, you can use arrow functions in the callback:

class LoggingButton extends React.Component { handleClick() { console.log('this is:', this); } render() { //This syntax ensures that `this` is bound within handleClick return ( <button onClick={(e) => this.handleClick(e)}> Click me </button> ); } }

One problem with this syntax is that a different callback function is created every time LoggingButton renders. In most cases, this is fine. However, if this callback is passed as a prop to lower-level components, those components may do extra re-rendering. We generally recommend binding in the constructor or using the property initializer syntax to avoid this kind of performance issue.


Passing arguments to event handlers

Usually we pass extra arguments to event handlers. For example, if id is the id of the row you want to delete, either of the following two ways can pass arguments to the event handler:

<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
The above two approaches are equivalent.

In the two examples above, the parameter e, as the React event object, will be passed as the second argument. With the arrow function approach, the event object must be passed explicitly, but with the bind approach, the event object and additional arguments will be passed implicitly.

It is worth noting that when passing arguments to a listener function via bind, for a listener function defined in a class component, the event object e should come after the passed arguments, for example:

class Popper extends React.Component{ constructor(){ super(); this.state = {name:'Hello world!'}; } preventPop(name, e){ //The event object e should be placed last e.preventDefault(); alert(name); } render(){ return ( <div> <p>hello</p> {/*Pass arguments via the bind() method.*/} <a href="https://reactjs.org" onClick={this.preventPop.bind(this,this.state.name)}>Click</a> </div> ); } }
Other extensions