Definindo um Componente
Componentes são, sumáriamente, um conjunto de nossos elementos que servem a um propósito final. São como funções, recebem algumas características e apresentam comportamento programável.
Todo o cerne de nossa aplicação gira em torno da composição de componentes, sua reutilização e seu comportamento e facetas por todo o projeto.
Neste texto, pretendo explicar e exemplificar as diferenças entre componentes declarados como funções, como classes e o que são props. Assim, daremos um primeiro passo em direção ao entendimento de estado e o ciclo de vida de nossos componentes.
Função ou Classe?
Podemos declarar um mesmo componente de duas grandes formas diferentes. Observe o código abaixo:
const Introducao = (props) => {
return <h1>Ola! Meu nome e {props.name}</h1>
}
No trecho de código acima declaramos um componente, composto por um elemento
que, com base nos textos passados, apresenta um valor variável props.name
. Perceba que acessamos a informação name
da mesma forma que acessaríamos o valor de um objeto.
A forma a qual declaramos o componente acima foi em formato de função. No caso, poderíamos também escrever:
function Introducao(props) {
return <h1>Ola! Meu nome e {props.name}</h1>
}
A primeira forma que escrevemos se caracteriza como uma arrow function
enquanto a segunda versão é uma função comum. Suas diferenças não cabem no momento, mas pretendo escrever sobre suas vantagens e desvantagens futuramente. De todo modo, na grande maioria dos casos, independente do uso, veremos os mesmos resultados em tela.
A outra grande forma de se declarar um componente é utilizando, e extendendo componente, em uma classe.
class Introducao extends React.Component {
render() {
return <h1>Ola! Meu nome e {this.props.name}</h1>
}
}
Classes são como nossas funções de componentes, só que com esteróides. Elas trazem uma série de características adicionais. Anteriormente, somente classes eram capazes de alguns efeitos que hoje, com os Hooks
, fizeram-se possíveis também nos componentes declarados por funções.
Mas isso é conversa pra uma outra hora.
Entendendo o que são props
Pra isso, precisamos entender que nossos elementos são representados por suas próprias tags. Vejamos o seguinte trecho de código:
const BomDia = <h1>Ola, bom dia!</h1>
const Introducao = <BomDia />
Chamando o elemento BomDia
como um componente, posso invoca-lo e utilizar seu conteúdo a medida do que julgar necessário. É neste ponto que a componentização começa a fazer um incrível papel de reutilização e organização do projeto.
Consideremos o seguinte trecho de código como nosso exemplo:
const Saudacao = props => {
return <h1>Ola, {props.name}, tenha um otimo dia!</h1>
}
const BoasVindas = <Saudacao name="Julieta" />
ReactDOM.render(
BoasVindas,
document.getElementById('root')
);
No trecho de código acima temos um exemplo de como as props
passam informações de componentes mais abrangentes para componentes mais específicos. As possibilidades são infinitas, levando em consideração que qualquer estrutura de dados pode ser o valor de uma prop.
Poderíamos então passar funções, objetos inteiros, arrays com dados, strings, numeros, o que for por props para alterar o comportamento ou aspecto de um componente diante de cada situação em que ele for chamado.
Um ponto importante quando utilizamos componentes: O JSX considera tags iniciadas em minúsculo como elementos HTML, enquanto tags iniciadas em letras maiúsculas são tratadas como componentes e, assim, devem estar presentes no escopo.
Imutabilidade das Props
Nossas props são imutáveis e devem permanecer como tal. A documentação do React nos dá um ótimo exemplo entre funções puras e impuras. Veja as seguintes funções retiradas da própria documentação para fins comparativos:
// Exemplo 01 - Funcao Pura
function sum(a, b) {
return a + b;
}
// Exemplo 02 - Funcao Impura
function withdraw(account, amount) {
account.total -= amount;
}
Podemos ver que na primeira função, seu resultado não altera seus parâmetros, garantindo os mesmos resultados sempre que passados os mesmos valores. Diferentemente, a segunda função altera diretamente um de seus parâmetros.
Em React, ambas as funções podem existir, exceto para um único caso: Quando tratamos de props, as funções devem ser sempre puras. Em outras palavras: As props recebidas devem ter sempre o mesmo valor. Todo papel de mutabilidade é delegado para uma outra parte do componente, denominada State
e que falaremos sobre ela futuramente.
Extraindo componentes: Dividir e conquistar
Uma das partes cruciais para se facilitar a reutilização de um componente é em particioná-lo em vários pedaços, montando nosso componente como um grande LEGO™.
const MeuComponente = props => {
return(
<div className="news">
<div className="header">
<h1>{props.title}</h1>
<h2>{props.subtitle}</h2>
</div>
<div className="content">
<p>{props.content}</p>
<p>{props.author.name}</p>
<img src={props.author.picture} />
</div>
</div>
)
}
Esta é uma forma de expressar nosso componente, porém é uma boa prática separarmos os componentes que nos convém e que podem ser reaproveitados em diversos outros componentes de nossa aplicação, como no exemplo a seguir:
const Header = (title, subtitle) => {
return(
<div className="header">
<h1>{title}</h1>
<h2>{subtitle}</h2>
</div>
)
}
const Content = (content, name, picture) => {
return(
<div className="content">
<p>{content}</p>
<p>{name}</p>
<img src={picture} />
</div>
)
}
const MeuComponente = props => {
return(
<div className="news">
<Header title="Extra, Extra!" subtitle="Julieta usa caixinha de areia!" />
<Content
content="Julieta usa caixinha de areia e impressiona moradores"
name="Vinicius"
picture="./foto-do-autor.jpeg"
/>
</div>
)
}
Perceba como cada pedaço do código exerce seu papel, com funções específicas e que se relacionam para formar o componente final.
Este conceito é essencial para se utilizar bem todas as ferramentas que o React nos fornece. No caso de uma classe
, nossos elementos em funções poderiam ser substituídos por métodos que nos retornam estes mesmos dados, com algumas diferenças na sintaxe.
class MeuComponente extends React.Component {
renderHeader = (title, subtitle) => {
return(
<div className="header">
<h1>{title}</h1>
<h2>{subtitle}</h2>
</div>
);
};
renderContent = (content, name, picture) => {
return(
<div className="content">
<p>{content}</p>
<p>{name}</p>
<img src={picture} />
</div>
);
};
getInfo = () => {
return {
title: "Extra! Extra!",
subtitle: "Julieta usa caixinha de areia!",
content: "Julieta usa caixinha de areia e surpreende moradores",
name: "Vinicius",
picture: "./foto-do-autor.jpeg"
};
};
render() {
const data = getInfo();
// Desestruturação do objeto data, vale a pena dar uma olhada sobre!
const { title, subtitle, content, name, picture } = data;
return(
{renderHeader(title, subtitle)}
{renderContent(content, name, picture)}
)
}
}
Conclusão
Esta parte é muito importante para entender a mecânica de como nossa cabeça tem que trabalhar, sempre dividindo bem as tarefas entre as funções e métodos que criam nossos elementos e componentes.
Portanto, minha recomendação é que a leitura deste artigo seja feita com muita calma e um olhar científico, no sentido de se estudar a um nível bem fracionado as informações que constam nas funções, nos conceitos e no fluxo.
No próximo texto, falarei sobre estado e sua manipulação.
Seu feedback é muito importante para que eu sempre melhore! :)
Até mais!
Top comments (2)
Que bom ler em português aqui no Dev. Parabéns pelos artigos. Comecei a te seguir :)
Obrigado Bruno! A iniciativa partiu da ideia de orientar alguns colegas de equipe mais novos, explicando o material que a gente encontra na grande maioria em inglês. Saber inglês é um diferencial, mas não é desculpa pra excluir quem não sabe! Forte abraço!