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

7

Using ES5 in development with ReactJS, 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, this references the object itself, which is the expected natural behavior. My question is how much does ES6 use 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 this references the instantiated object itself when using the new operator, can anyone tell me what the actual purpose of using bind is? Is it something related to React's internal mechanisms?

    
asked by anonymous 06.05.2016 / 15:46

2 answers

7

% of dynamic%

this solves a problem caused by the context of bind , it provides a way to ensure that even by decoupling a function from an object its behavior remains the same, thus ensuring integrity of the behavior of the function. This is interesting in the case of JavaScript , where the ideal is programação funcional terms, which have as part of their ideology a non-collateral function. 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 in our system. Note that it does not use funções puras , and because we are using the bind object, the context of the function suffers no problem at all. The problems of not using a johnDoe (or another solution) in this case only appear when we uncouple the function from 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 uncouple a function for a variable, the context of the function becomes the global context, so its behavior is completely broken. Note that the problem also occurs when you pass the function as a 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 of bind , where we register a function to listen for an event we also have a similar problem, because the function context is modified in the event listener call. When the function registered in an event is called, the scope of the function becomes the element that triggered the action. Since DOM is an event, if onClick was not done, it 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);

Problem example: link

    
06.05.2016 / 18:23
4

As Gabriel's answer is already quite complete, I'll leave a tip here (which does not answer the question - making it clear right away) that makes it much easier to use React in ES6.

Instead of using method definitions to declare our methods, we can declare them as properties using arrow functions , which already causes the method to lexically link this , making it independent of how / where it is called, will use the this of the 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: declaring properties outside constructor is called Class Instance Field and is still on Stage 1 to be considered standard. To declare the properties in this way already, you will need a transpiler like TypeScript or Babel (with Stage 1 enabled).

If you did not want to do this, you can declare it inside the constructor, using this before:

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

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

    
07.05.2016 / 06:58