Why is it necessary to use bind when working with ES6 and Reactjs?

Asked

Viewed 2,357 times

8

Using ES5 in Reactjs development, a component can be declared as follows:

var MyComponent = React.createClass({
  alertSomething: function(event) {
    alert(event.target);
  },

  render: function() {
    return (
      <button onClick={this.alertSomething}>Click Me!</button>
    );
  }
});

ReactDOM.render(<MyComponent />);

In this example the this refers to the object itself, which is the expected natural behavior. My doubt is how much ES6 is used to create components.

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
  }

  alertSomething(event) {
    alert(event.target);
  }

  render() {
    return (
      <button onClick={this.alertSomething.bind(this)}>Click Me!</button>
    );
  }
}

ReactDOM.render(<MyComponent />);

Knowing that in Javascript the this references the instantiated object itself when using the operator new, someone can tell me the real purpose of using bind? Something related to React’s internal mechanisms?

2 answers

8

this dynamic

The bind solves a problem caused by the context of JavaScript, It provides a way to ensure that even decontaminating a function of an object its behavior remains the same, thus ensuring an integrity of the function’s behavior. This is interesting in the case of programação funcional, where the ideal is terms funções puras, which they possess as part of their ideology be a function without side effect. An example of the problem:

function Usuario() {
  this._nome = '';

  this.setNome = function(nome) {
    this._nome = nome;
  };

  this.getNome = function() {
    return this._nome;
  };
}

var johnDoe = new Usuario();

johnDoe.setNome('John Doe');

console.log(johnDoe.getNome()); // 'John Doe'

Here we have a simple constructor function that serves to represent the user entity on our system. Note that it does not use bind, and we’re using the object johnDoe, the context of the function does not suffer any problem. The problems of not using a bind (or other solution) in this case only appear when we decouple the function of the object.

var johnDoe = new Usuario();
var setNome = johnDoe.setNome;
setNome('John Doe');

console.log(johnDoe.getNome()); // ''
console.log(window._nome)); // 'John Doe'

When we decouple a function to a variable, the context of the function becomes the global context, then its behavior is totally broken. Note that the problem also occurs when you pass the function as parameter to another function.

var johnDoe = new Usuario();

function popularNome(setNome) {
  setNome('John Doe');
}

popularNome(johnDoe.setNome);

console.log(johnDoe.getNome()); // ''
console.log(window._nome)); // 'John Doe'

When we work with events from DOM, Where we record a function to listen to an event we also have a similar problem, because the context of the function is modified in the call by the event listener. When the function recorded in an event is called, the scope of the function becomes the element that triggered the action. Like the onClick is an event if the bind were not done, he would have this problem:

var usuario = {
  _nome: '',
  setNome: function(event) {
    this._nome = event.target.value;
  }
};

var elNome = document.getElementById('nome');

// O contexto da função setNome seria
// equivalente ao "elNome"
elNome.addEventListener('keyup', usuario.setNome);

Example of the problem: https://jsfiddle.net/fvenq166/

5

As Gabriel’s answer is already quite complete, I will leave here a tip (that does not answer the question - making it clear from now on) that greatly facilitates the use of React in ES6.

Instead of using method Definitions to declare our methods, we can declare them as properties using Arrow functions, which already cause the method to link lexically the this, making it independent of how/where it is called, will use the this class.

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
  }

  alertSomething = (event) => {
    alert(event.target);
  };

  render() {
    return (
      <button onClick={this.alertSomething}>Click Me!</button>
    );
  }
}

ReactDOM.render(<MyComponent />);

Note: the declaration of properties outside the constructor is called Class Instance Field and is still in Stage 1 to be considered standard. To declare the properties in this way, you will need a transpilator like Typescript or Babel (with Stage 1 enabled).

If you didn’t want to do this, you can declare it inside the builder, using the this before:

constructor(props) {
  super(props);
  this.alertSomething = (event) => {
    alert(event.target);
  };
}

A final remark: in your example, even if you do not use the bind in ES6, everything will work perfectly well, you will only have problems when you want/have to use the this.

  • 1

    +1 because of the citation of Class Instance Field

Browser other questions tagged

You are not signed in. Login or sign up in order to post.