Why do we need bind or arrow functions?

Suppose that you have a component in which you have the defined the state as following:

constructor(props) {
        super(props);
        this.state = {
            fullName: '',
        }
    }

You get this.state.fullName from a textbox by handling the onChange event:

<input name="fullName" value={this.state.fullName} type='text' onChange={this.onChanged}></input>

So you create an event handler for it:

onChanged({target}){
        this.setState({ fullName: target.value});
    }

But as soon as you enter some text in this text box, you encounter the following error:

Uncaught TypeError: Cannot read property 'setState' of undefined

The reason behind it is that custom class methods are not bound by default in Javascript. You have to explicitly bind them in order to make the work.

How to bind class methods

In order to bind the class methods to properly handle events, we can try any one of the following methods:

Bind the method in the constructor

constructor(props) {
        super(props);
        this.state = {
            fullName: '',
        }

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

Bind directly when calling the method

<input name="fullName" value={this.state.fullName} type='text' onChange={this.onChanged.bind(this)}></input>

Call the method using arrow functions

<input name="fullName" value={this.state.fullName} type='text' onChange={(e) => this.onChanged(e)}></input>

Define the class method as an arrow function

onChanged = ({target}) => {
        this.setState({
            [target.name]: target.value
        });
    }

Tip: Notice how the target is used to get the name and value as well from the event. This is possible when you define both the name & value in the JSX element. For example:

<input name="fullName" value={this.state.fullName} type='text' onChange={this.onChanged}></input>

Notice the name & value in the above element.

How to pass parameters to event handlers

Pass parameter using bind directly

You can pass parameters to an event handler using the following methods:

<input name="fullName" value={this.state.fullName} type='text' onChange={this.onChanged.bind(this, 'Parameter')}></input>

You can receive the parameter in the event handler in the following way:

onChanged(id, {target}){
        console.log('Incoming id: ' + id);
        this.setState({
            [target.name]: target.value
        });
    }

Pass parameter by invoking as arrow function

<input name="fullName" value={this.state.fullName} type='text' onChange={(e) => this.onChanged('MyParameter', e)}></input>

Note: In both of the above examples, e is passed after our parameter as the next parameter. In the case of bind, all the further arguments are automatically forwarded including e so we don’t need to pass it in explicitly. But we need to explicitly pass it in the case of arrow functions.