React/ReactJS: Handling Events

There was once a habit of registering event handlers as HTML attributes as shown below.

<input type="radio" value="trillium" onclick="checkFlower()"
	name="flower"/> Trillium<br/>
trillium flower Great White Trillium by Bernard B. ILarde. CC BY-SA 3.0

Once the click event occurs, the onclick event handler calls the checkFlower() function defined somewhere inside the <script> element.

function checkflower(){
	// do something
}

This practice is not recommended anymore, unless, of course, you are working on an archaic IE8/Opera 6 compatible web application which do not support the addEventListener() method.

But in JSX, using inline event handlers happen to be a norm. Just that events in JSX are written in camelCase, like onClick, onChange, onMouseOver, onPointerDown, etc.

The above HTML tag with an event handler can be rewritten in JSX as:

<input type="radio" value="trillium" onClick={(e) => this.checkFlower(e)}
	name="flower"/> Trillium<br/>

Now since any method defined inside an ES6 class inherits bind() from the Function prototype, we can also write it as:

<input type="radio" value="trillium" onClick={this.checkFlower.bind(this)}
	name="flower"/> Trillium<br/>

The checkFlower() function is defined somewhere inside the component, and is known as a callback function (generally just "callback"), and e is the synthetic event.

checkFlower(e) {
  console.log('flower: ', e.target.value);
}

But again, such practice of binding in property or render is not encouraged because everytime the component renders, it creates a new function.

Binding of the callback function should be done in the constructor (ES6). Notice that bind() is not used inside the JSX anymore.

class Flower extends React.Component {
	constructor(props) {
    	super(props);
    	this.checkFlower = this.checkFlower.bind(this);
	}
	checkFlower(e) {
  		console.log('flower: ', e.target.value);
	}
  	render() {
	    return (
	    	<label>
	    		<input type="radio" value="trillium"
	    			onClick={this.checkFlower} name="flower"/>
	    			Trillium
	    	</label>
		);
  	}
}

Now there is another way where we can do away with the mandatory bindings either inside the constructor or the JSX and do it in the method definition itself.

checkFlower = (e) => {
	console.log('flower: ', e.target.value);
}

The syntax is elegant, but is still experimental (not-standardized).

Passing Extra/Additional Parameters

Also we may need to send additional parameters besides the synthetic event e. As in JavaScript, we do this by sending a comma-separated list of arguments after this.

<input type="radio" value="trillium"
	onClick={this.checkFlower.bind(this, '3')}
	name="flower"/> Trillium<br/>

Or if the binding is done properly inside the constructor:

constructor(props) {
	super(props);
	this.checkFlower = this.checkFlower.bind(this, '3');
}

But inside the callback, the synthetic event e occurs last in the order of parameters.

checkFlower(petals, e) {
  console.log("petals: ", petals, ', flower: ', e.target.value);
}