O construtor está morto, viva o construtor!

Diga adeus ao construtor da classe medieval em seus componentes React.

Foto de Samuel Zeller sobre Unsplash

Enquanto os Componentes de Função sem Estado (SFCs) são uma ferramenta acessível no seu arsenal, os Componentes da Classe ES6 ainda são a maneira de fato de escrever os componentes do Reactor que utilizam ganchos de estado ou ciclo de vida.

Um componente de classe ES6 hipotético pode parecer algo assim (simplificado sem verificação de erro, é claro).

 classe Foo extends Componente { 
construtor (adereços) {
super (adereços);
this.state = {loading: true};
}
 componente assíncronoDidMount () { 
dados constantes = aguardar loadStuff ();
this.setState ({loading: false, data});
}
 render () { 
const {loading, data} = this.state;
Retorna (
{Carregando ? <Carregando />: <Visualizar {... dados} />}
);
}
}

Inicializamos nosso state no constructor , carregamos nossos dados de modo assíncrono em componentDidMount e tornamos nosso componente View baseado no estado de loading . Um padrão bastante padrão – pelo menos para mim, se você acompanha meu trabalho.

Propriedades da classe

Nós fomos ensinados que o constructor é onde nós inicializar nossas propriedades de instância, state neste caso. E se você está se dizendo: "Exatamente!", Então você estaria absolutamente correto … se não fosse pela próxima proposta de propriedades da classe ES.next, atualmente no estágio 3.

Com isso, podemos agora definir propriedades de classe diretamente, assim.

 classe Foo extends Componente { 
state = {loading: true};
...
}

Babel irá transpilar seu código e adicionar um constructor para você nos bastidores. Aqui está o resultado da Babel quando transpilamos o trecho de código acima.

Note que Babel está realmente passando todos os args – não apenas props – até super . Também está levando o valor de retorno do super e passando de volta ao chamador. Ambos podem ser um pouco exagerados, mas exatamente o que deveria estar fazendo.

Ainda há um construtor, você simplesmente não vê.

Métodos de ligação

Outra razão pela qual somos ensinados a usar o constructor é para métodos vinculativos para this , assim.

 classe Foo extends Componente { 
construtor (adereços) {
super (adereços);
this.myHandler = this.myHandler.bind (this);
}
 myHandler () { 
// algum código aqui que faz referência a este
}
...
}

Algumas pessoas ignoram isso tudo ao atribuir uma expressão de função a uma propriedade de classe, mas essa é uma história diferente. Leia mais sobre isso no meu outro artigo do ES6 React Classes Demystifying Memory Usage usando ES6 React Classes .

Desmistificando o uso da memória usando ES6 React Classes
Qual é mais eficiente? Ligação no construtor, ou usando uma função de seta como uma propriedade de classe? medium.com

Vamos assumir por um momento que você está no campo de bind (e, mesmo que não esteja, tenha paciência comigo). Precisamos ligar no constructor , certo? Não necessariamente. Podemos fazer o mesmo que fizemos pelas propriedades da classe acima.

 classe Foo extends Componente { 
myHandler = this.myHandler.bind (this);
 myHandler () { 
// algum código aqui que faz referência a este
}
...
}

Inicializando o estado com adereços

E quando você precisa derivar seu state inicial de props , digamos para inicializar um valor padrão? Certamente, precisamos do constructor para isso?

 classe Foo extends Componente { 
construtor (adereços) {
super (adereços);
this.state = {
cor: this.props.initialColor
};
}
 render () { 
const {color} = this.state;
Retorna (
<div>
{cor}
</ div>
);
}
}

Não! Mais uma vez, as propriedades da classe para o resgate! Temos acesso a ambos this e props .

 classe Foo extends Componente { 
state = {
cor: this.props.initialColor
};
...
}

Pesquisa de dados

Talvez precisemos de um constructor para buscar dados? Dificilmente. Como vimos em nossa primeira amostra de código, qualquer carregamento de dados deve ser feito em componentDidMount . Mas por que componentDidMount ? Nós o fazemos lá para que a busca não seja executada ao executar o componente no servidor – como é o caso ao fazer o Renderização do lado do servidor (SSR) – como componentDidMount não é executado no lado do servidor.

Conclusão

Nós vimos isso para configurar nosso state inicial, já não precisamos de um constructor (ou de qualquer outra propriedade de instância para esse assunto). Nós também não precisamos disso para métodos vinculativos para this . O mesmo para configurar o state inicial dos props . E, definitivamente, nunca obteremos dados no constructor .

Por que, então, precisamos do constructor em um componente React?

Bem … você não.

[No entanto … Se você encontrar algum caso de uso obscuro em que você precisa inicializar algo em um componente, tanto do lado do cliente como do lado do servidor, você ainda possui um out. Sempre há componentWillMount . Internamente, Reagir chama este gancho logo após "novo" a classe (que chama o constructor ) no cliente e no servidor.]

Então eu mantenho isso para os componentes do React: o construtor está morto, viva o construtor!

Texto original em inglês.