Binding in React

superkarolis

Karolis Ramanauskas

Posted on May 30, 2018

Binding in React

Before the release of React v0.13 using methods in React components was very straightforward since the traditional React.createClass automatically bounded user defined methods to the correct this context.

However, since the introduction of ES6 classes in React components, the methods are no longer automatically bound. As a result, we have at least four ways to handle this context in React. Let’s consider the advantages and disadvantages of each.

Bind in render

This approach works by allocating this to a given function on each render call. The downside of this approach is that the function is reallocated on each render. Whilst for most applications the performance implications of this are negligible, it's still something to keep in mind.

class LogThis extends Component {
    handleClick() {
        console.log('this is:', this);
    }

    render() {
        return (
            <button onClick={this.handleClick.bind(this)}>
                Click me
            </button>
        );
    }
}

Enter fullscreen mode Exit fullscreen mode

Arrow functions in render

This approach makes use of ES6 fat-arrow functions which help preserve the context of this by using lexical scoping. For those non-familiar with lexical scoping, it just means that a function uses this from the code that contains the arrow function.

Since this in render function always refers to the containing React component, and fat-arrow function uses lexical scoping, handleClick retains the component's this.

It stil has the downside of the previous approach in that a diffrent callback is created on each rerender and thus may cause performance issues.

class LogThis extends Component {
    handleClick() {
        console.log('this is:', this);
    }

    render() {
        return (
            <button onClick={e => this.handleClick(e)}>
                Click me
            </button>
        );
    }
}

Enter fullscreen mode Exit fullscreen mode

Bind in constructor

One way to avoid performance downsides of previous two approaches is to bind in the constructor. This approach is currently recommended by the official React documentation and it's also the approach I have adopted on my projects.

The main downside of this approach is having to repeatedly bind each function in the constructor. If there are several functions in the component to be bound, it may start looking ugly quick.

class LogThis extends Component {
    constructor(props) {
        super(props);
        this.state = { message: 'Hello, world!' };
        this.handleClick = this.handleClick.bind(this);
    }

    handleClick() {
        console.log('this is:', this);
    }

    render() {
        return (
            <button onClick={this.handleClick}>
                Click me
            </button>
        );
    }
}

Enter fullscreen mode Exit fullscreen mode

Class fields

The final way to bound this is by using experimental public class fields syntax.

This approach is the most superior of all because it avoids the performance issues of reallocating functions on each render. And it also removes unnecessary repetition when binding functions in the constructor.

One notable disadvatange of this approach is that by declaring methods in such a way, handleClick is not declared in the prototype and thus is impossible to be called via super.handleClick from the derived class.

class LogThis extends Component {
    handleClick = () => {
        console.log('this is:', this);
    }

    render() {
        return (
            <button onClick={this.handleClick}>
                Click me
            </button>
        );
    }
}

Enter fullscreen mode Exit fullscreen mode

Extra: use react-autobind

The final extra and from what I can tell, a non-conventional way to handle binding in React ES6 classes is by using npm module react-autobind. It has all the advantanges of binding in constructor, plus you get to avoid repetition by having to bind each function separately.

The disadvantage is that an additional npm module has to be imported and you still have to call autoBind in the constructor.

import autoBind from 'react-autobind';

class LogThis extends Component {
    constructor() {
        super();
        autoBind(this);
    }

    handleClick() {
        console.log('this is:', this);
    }

    render() {
        return (
            <button onClick={this.handleClick}>
                Click me
            </button>
        );
    }
}

Enter fullscreen mode Exit fullscreen mode

Summary

I personally see no real benefits of using binding or arrow functions in render. There are no real readability benefits as far as I'm concerned and the performance is negatively impacted, even if negligibly.

Thus, if you are willing to use Babel stage-2 preset and will not have to call a parent function from derived class, I would recommend using class fields approach to binding.

Otherwise, I would recommend binding in the constructor either by binding each function manually, or using react-autobind module. Both are fine and comes down to personal preference. If there are several functions to be bound, I would use react-autobind and if it's just one or two, go with the conventional approach.

💖 💪 🙅 🚩
superkarolis
Karolis Ramanauskas

Posted on May 30, 2018

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Binding in React
react Binding in React

May 30, 2018