ReactJS: Function x Class component

A partir da versão 16.8 do ReactJS algumas atualizações foram implementadas, permitindo que a criação de componentes se tornasse mais fácil e menos verbosa. Neste artigo iremos abordar a diferença entre criar componentes de classe e componentes funcionais, para que você escolha qual se adapta melhor ao seu projeto.

Jessica Meira

Jessica Meira

June 04, 2021 | leitura de 8 minutos

dev

Que os Hooks do ReactJS não são mais novidade, já sabemos, mas eles ainda causam um pouco de espanto - principalmente se você está chegando agora e não entende o motivo de alguns componentes serem escritos com classe e outros com função. Se esse é o seu caso, assim como já foi o meu, pegue uma cadeira e sente-se confortavelmente que eu tentarei sanar as suas dúvidas.

Componentes

Para entender sobre a diferença entre componente funcional e componente de classe dentro do React, tenha em mente que componentes são os responsáveis por permitir a divisão da interface em partes independentes e reutilizáveis. 

A maior diferença entre ambas as formas é a sintaxe. A utilização das funções é também mais reforçada devido ao código ser mais enxuto e a possibilidade de utilização dos hooks, ainda que haja funcionalidades específicas para os componentes de classe.

Componentes funcionais e componentes de classe

Não é difícil encontrar diversos projetos com componentes sendo criados a partir de classes, com a atualização do React para a versão 16.8, o padrão recomendado se tornou a function, já que nas versões anteriores os states não podiam ser utilizados em componentes funcionais. Dessa maneira, quando havia a necessidade de alteração ou de manipulação de algum state, era necessário que o componente fosse alterado para uma classe.

Vou mostrar como este processo era realizado anteriormente, e qual é a maneira recomendada hoje. Assim, você conseguirá ver na prática quais mudanças ocorreram. 

Caso você queira testar os exemplos apresentados aqui, o projeto pode ser criado através do comando: npx create-react-app nomedoprojeto

Por padrão, as versões mais recentes criam a aplicação utilizando os modelos de função.

Componentes de classe

Antes, a sintaxe mais facilmente encontrada era algo parecido com essa:

import React from  'react';

class  App  extends  React.Component {

  render() {

    return(

      <div  className="App">

        <h1>Olá, </h1>

      </div>

    );}

}

export  default  App;

Agora, podemos criar um outro componente, a fim de reaproveitar o código. Veja:

import React from  'react';

class  MyText  extends  React.Component{

  render(){

    return <h1>Olá Pessoa/mundo </h1>

  }

}

class  App  extends  React.Component {

  render() {

    return(

      <div  className="App">

        <MyText />

  <MyText />

  <MyText />

      </div>

    );}

}export  default  App;

A nível de instrução, todo componente definido pelo usuário tem que, obrigatoriamente, começar com letra maiúscula.

O componente pode ser chamado várias vezes, sem problema nenhum. Aí, você me pergunta: "Por que eu iria chamar o mesmo componente várias vezes com o mesmo texto?" Que bom que você perguntou! Na verdade, eu só fiz isso para apresentar as props.

O que são props?

Segundo a própria documentação do ReactJS, as props ou propriedades são os parâmetros que você passa para o seu componente. Por exemplo:

<MyText  name="Mundo"/>

Elas podem ter qualquer valor, exatamente como na função, quando eu invocar as props dentro do meu componente, será recebido tudo o que foi passado.

Dentro do componente as props são lidas assim:

return <h1>Olá, {this.props.name}</h1>

O Exemplo ficará assim:

import React from  'react';

class  MyText  extends  React.Component{

  render(){

    return <h1>Olá, {this.props.name}</h1>

  }

}

class  App  extends  React.Component {

  render() {

    return(

      <div  className="App">

        <MyText  name="Mundo"/>

        <MyText  name="Pessoa"/>

        <MyText  name="Ateliware"/>

        <MyText  name="Jessica"/>

      </div>

    );}

}

export  default  App;

Também é possível que esse meu componente aceite outros parâmetros vindos como props, exemplo:

import React from  'react';

class  MyText  extends  React.Component{

  render(){

    return <h1>Olá {this.props.local}! Eu sou uma {this.props.gender} chamada {this.props.name}</h1>

  }

}

class  App  extends  React.Component {

  render() {

    return(

      <div  className="App">

        <MyText  local="Mundo"  gender="Pessoa"  name="Jessica" />

      </div>

    );}

}

export  default  App;

Entendido o conceito das props, é importante saber que o há outro método utilizado em classe para cuidar dos states, ou seja, estados do meu componente.

States

Aqui começamos a entender como podemos alterar o valor ou estado das informações que temos no nosso componente. Este método é similar às props, porém privado.

Para explicar, trarei um exemplo um pouco diferente. Ao usar o this.state, como já mencionado anteriormente, é necessário que os componentes sejam declarados como classe, visto que estamos trabalhando desta forma podemos seguir adicionando o construtor na classe onde o estado do componente será alterado.

Conforme a documentação, o constructor é um método especial para criar e iniciar um objeto criado pela classe. Só pode existir um método com o nome constructor dentro da classe.

É importante entender que você não poderá utilizar o this em um construtor sem antes ter chamado o construtor pai. Isso é feito utilizando a palavra-chave super.

import React from  'react';

class  MyText  extends  React.Component{

  render(){

    return <h1>Clicado: {this.props.text}</h1>

  }

}

class  MyButton  extends  React.Component{

  render(){

    return(

      <button 

      onClick={() => {this.props.handleClick(this.props.button)} }>

      {this.props.button}

      </button>

    )

  }

}

class  App  extends  React.Component {

  constructor(props){

    super(props);

    this.state = {

      mylabel:  ""

    }

  }

  setMyLabel = (mylabel) => {

    this.setState({ mylabel });

  }

  render() {

    return(

      <div  className="App">

        <MyText  text={this.state.mylabel} />

        <MyButton  handleClick={this.setMyLabel}  button="botão1" />

        <MyButton  handleClick={this.setMyLabel}  button="botão2" />

      </div>

    );}

}

export  default  App;

Entendendo o código:

  • Adicionado o construtor (constructor) e chamando o construtor pai (super) dentro da classe App;
  • No construtor é informado o valor inicial do elemento que será alterado através do this.state;
  • Declarado o método responsável por manipular o estado do nosso componente;

Partindo para a chamada desse método e renderização do componente, é passado o método responsável por atualizar o estado da mesma maneira que as props, ou seja, o nome e o valor, que no exemplo é: handleClick={this.setMyLabel} .

Dentro do componente MyButton será chamado a props que contêm este método, e também será passado como parâmetro o novo valor. Assim: onClick={() => {this.props.handleClick(this.props.button)} }>

Se você já está familiarizado com o React pode estar se perguntando sobre o ciclo de vida e seus métodos, mas isso podemos deixar para um próximo post. Que tal?

Até aqui entendido, de uma maneira mais direta e simples sobre a funcionalidade dos componentes de classe, vamos virar a chave e entender sobre outra maneira de declarar um componente.

Componentes de função

Nos componentes declarados como função temos algumas diferenças de sintaxe e os hooks, o que, atualmente, possibilita e facilita na sua usabilidade.

A base da função seria chamada dessa forma:

function  App(props) {

  return (

    <div  className="App">

      <p>Olá, {props.name}</p>

    </div>

  );

}

export  default  App;

Ou seja, utilizando as props sem problemas, porém sem mudança e manipulação através do this.state e sem a necessidade do método render.

Hooks

Eles permitem que você use o state e outros recursos sem criar uma classe para isso. As maravilhas da modernidade, não é mesmo?

As principais motivações para implantação dos hooks segundo o núcleo do React foram: A dificuldade em entender alguns componentes quando muito complexos e extensos, e a confusão para os novos desenvolvedores, onde a maneira de utilizar os estados acabava se tornando uma barreira no aprendizado do framework.

Caso você queira saber de maneira mais detalhada sobre o que levou a essa mudança, aqui tem um link super interessante. 

Uma definição bem resumida encontrada na documentação é:

"Hooks são funções que permitem a você 'ligar-se' aos recursos de state e ciclo de vida do React a partir de componentes funcionais. Hooks não funcionam dentro de classes --- eles permitem que você use React sem classes."

Então, vamos de exemplo. Quando dizemos que atualmente os componentes se tornaram mais simples de se escrever, é devido a situações similares a esta:

import React, { useState } from  'react'

function  App() {

  const [name, setName] =  useState("Forasteiro");

  return (

    <div  className="App">

      <p>Olá {name} </p>

      <button  onClick={() =>  setName("Viajante do tempo")}> 

      Click Me

      </button>

    </div>

  );

}

export  default  App;

Primeiro, há a importação do useState diretamente do React. Nós já entendemos que ele é um hook que nos permite manipular o state dentro de funções, mas o que ele faz? 

Ele declara uma array onde o primeiro elemento manterá o estado inicial, que serve para preservar alguns valores entre as chamadas de função e o segundo elemento responsável por manipular os valores atuais.

A maneira como é informado o estado inicial da variável será informando-o como parâmetro para o useState().

Observando o exemplo, há a declaração de um array com dois valores, seguido do useState e um valor passado por parâmetro.

const [name, setName] = useState("Forasteiro") 

O valor que está sendo passado por parâmetro será o valor inicial do estado. Ele será atribuído ao primeiro elemento dentro do array, ou seja, ao name. O segundo elemento setName será o responsável por alterar o estado do componente. 

Para apresentar os valores que no nosso exemplo, caso fosse com classe seria this.state.name. Agora, com função é utilizado apenas o name diretamente.

A atualização desse estado também não poderia ser complicada, no caso do exemplo estamos lidando com um botão, então no click deste botão é chamado apenas o setName que irá atualizar o estado atual, passando por parâmetro qual será o novo valor.

Na prática, a diferença para o componente de classe, com o mesmo comportamento, seria assim:

import React from  'react';

class  ExemploClasse  extends  React.Component {

  constructor(props){

    super(props)

    this.state = {

        name:  "Forasteiro"

    }

  }

  render(){

    return (

      <div  className="App">

        <p>Olá {this.state.name} </p>

        <button  onClick={() =>  this.setState({ name:  "Viajante do tempo"})}> 

        Click Me

        </button>

      </div>

    );

  }

}

export  default  ExemploClasse

Ou seja, um pouco maior e consequentemente mais confuso para quem inicia no React.

Conclusão

Agora que ambas as formas foram apresentadas, fica a seu critério escolher a que faz mais sentido para você. Lembrando que até a publicação deste artigo o React não tem planos de descontinuar as classes, então você não precisa se preocupar, já que a inserção dos hooks aconteceu em fevereiro de 2019. Não é algo novo, mas ainda causa um pouco de confusão. Por esse motivo, o intuito deste artigo foi apenas apresentar as duas formas e demonstrar algumas diferenças entre elas. 

Referências
Component and props
React: Getting Started
React Component
Hooks Reference
Hooks State
Jessica Meira
Jessica Meira

Software Engineer | Cursando pós-graduação em Inteligência Artificial, um pouco curiosa nas horas vagas. Mais de 15 anos na área de Tecnologia e apaixonada por música e instrumentos.

LinkedIn