9
respostas

Resolver o problema com excessivos bind's

9 respostas

Oi Alessandro, tudo bem? Desculpa, não entendi bem seu tópico, poderia explicar?

Não é bem uma dúvida a ser solucionada. Está mais para uma dica. Que ao aprender React percebe-se a necessidade de colocar objetos e funções no contexto sendo obrigado a fazer o bind dos mesmos. Com esse plugin se torna mais fácil.

Pelo que entendi o plugin permite adicionar propriedades/atributos/campos dentro do corpo de uma classe. Ao invés de ter que fazer isso pelo construtor, ou no caso de propriedades de estáticas, fora da classe:

class NomeClasse {
    // Prop estática
    // static valor = 10
}

NomeClasse.valor = 10

Deixa mais parecido com Java.

Mas não entendi como isso ajuda a resolver o problema dos bind's.

Declarar propriedade como estática, na prática, ela terá o mesmo valor para todos os objetos da classe. Não vejo isso como uma boa prática a não ser que realmente faça sentido.

O truque para se livrar dos binds é usar arrow-function :)Façam os cursos de Javascript avançado do Flávio e mandem ver :)

Estava lendo um artigo do Cory House sobre abordagens para se trabalhar com o this no React e finalmente entendi o que o Alessandro quis dizer.

Uma das abordagens é usar o bind ao passar a função como propriedade:

onChange={this.handleChange.bind(this)}

Outra é usar uma Arrow Function:

onChange={e => this.handleChange(e)}

Mas como o autor aponta, as duas maneiras geram uma nova função a cada renderização, o que pode gerar problemas de performance.

Por isso o autor mostra outra maneira, fazer o bind no construtor:

constructor(props) {
  super(props);
  this.handleChange = this.handleChange.bind(this);
}

Finalmente, o autor mostra uma maneira utilizando arrow functions em propriedades de classe:

class HelloWorld extends React.Component {
  // Note that state is a property,
  // so no constructor is needed in this case.
  state = {
    message: 'Hi'
  };

  logMessage = () => {
    // This works because arrow funcs adopt the this binding of the enclosing scope.
    console.log(this.state.message);
  };

  render() {
    return (
      <input type="button" value="Log" onClick={this.logMessage} />
    );
  }
}

Atualmente não é possível utilizar propriedades em classes, ou seja, não tem como declarar uma arrow function dessa maneira em uma classe, nem a propriedade state da maneira que foi declarada. Normalmente ela estaria dentro do construtor.

Existe uma proposta ao EcmaScript para adicionar campos/propriedades/atributos de classe, inclusive o tão pedido campo privado. Desta maneira seria possível utilizar os atributos como no exemplo acima.

A proposta foi para o estágio 3 em 27/08/2017 commit 5a4ff5fa4bf30885188279f6fb8070f2e1903c32 no repositório git.

Enquanto a proposta não é aprovada, foi criado o plugin para o babel (Class properties transform mencionado aqui pelo Alessandro) que permite usar a sintaxe com atributos de classe e transpila o código.

Vale notar que o plugin do babel não adiciona a função no prototype da classe, mas adiciona no construtor da mesma. Isso significa que caso você estenda a classe onde foi utilizada a função como propriedade, a classe filha não poderá chamar o método da classe mãe.

Exemplo de código no babel:

class AtributoClasse {
  state = { valor: 10 }

  boundFunction = () => {
    return this.state.valor
  }
}

Transpilado:

"use strict";

function _classCallCheck(instance, Constructor) {
  if (!(instance instanceof Constructor)) {
    throw new TypeError("Cannot call a class as a function");
  }
}

var AtributoClasse = function AtributoClasse() {
  var _this = this;

  _classCallCheck(this, AtributoClasse);

  this.state = { valor: 10 };

  this.boundFunction = function () {
    return _this.state.valor;
  };
};

Pelo código transpilado fica claro que a boundFunction é criada no "construtor", ou seja, para cada instância será criada uma nova boundFunction, não há a "herança" disponibilizada pelo prototype.

Alguns dos exemplos que usei vieram do artigo do Cory House no blog do freeCodeCamp, vale a pena dar uma olhada.

Então, como quase tudo no ES6 é syntax sugar, inclusive a ideia de classes, por baixo dos panos, a ideia continua sendo ES5 na prática. Apenas abstraído. Então o que você fizer no constructor do ES6, vai ser aplicado dessa forma.

Eu vi que ele realmente fala em possíveis problemas de performance, mas eu concordo com a ideia do Akita onde, se preocupar com isso antes de ter algo idealmente funcionando é otimização prematura e talvez desnecessária. Performance é importante, sim, mas acredito que seja melhor pensar nisso depois de ter algo funcional, com testes, como uma refatoração.

Wanderson, muita gente experiente diz isso, em relação a não se preocupar com performance até que você tenha problemas de performance.

Em parte eu concordo, acho muito complicado ter que pensar em cada linha de código e ficar raciocinando o melhor algoritmo possível pra performance.

Mas em casos como este, onde a decisão é fácil de ser tomada, e a abordagem mais performática é simples de ser implementada, mesmo sem ter muita experiência, acredito que valha mais a pena implementar a abordagem mais performática.

Acho muito pior, no futuro ter que ficar caçando onde está o problema pra consertar, simplesmente por ter tomado uma decisão com base sintática.

Acho que faz muito sentido sim, não discordo, mas como expliquei, acho preferível pensar nisso depois. Por que? Por que os gargalos de performance não dependem diretamente de como o código foi escrito em muitos casos. Claro que pode ser algo no código, sem dúvida, um laço mal feito pode levar a app a ruína, mas na Web há outros problemas bem mais urgentes do que como você escreveu o método.

Eu pessoalmente prefiro escrever o código da forma que sei hoje e entendo como funciona do que procurar precocemente a melhor forma de escrever. Prefiro voltar depois, com mais experiência, olhar como fiz, refatorar e otimizar.

As boas práticas evoluem e mudam assim como a forma que você escreve o código conforme vai passando o tempo e você vai ganhando experiência, é o caminho natural. Até 2, 3 anos atrás comprimíamos todo o CSS em um .min só, hoje, usamos vários .min para se aproveitar do HTTP/2.

Mas no mínimo lhe devo parabéns por ter ido mais a fundo. Por ter pesquisado, estudado a melhor forma e ainda ter compartilhado. Só não fique muito bitolado com isso sempre.

Parabéns e obrigado pela discussão! :)

Opa, eu quem agradeço Wanderson!

Quer mergulhar em tecnologia e aprendizagem?

Receba a newsletter que o nosso CEO escreve pessoalmente, com insights do mercado de trabalho, ciência e desenvolvimento de software