Trabalhando e conhecendo Componentes

Trabalhando e conhecendo Componentes

E então, pronto para criar seus primeiros componentes em ReactJS?

Se sim, maravilha, o primeiro passo é sempre importante para darmos o pontapé inicial na sua jornada como desenvolvedor ReactJS.

Pois bem, se você está comigo desde o início, sabe que o ReactJS é um framework baseado em componentes (components), onde a ideia é criar interfaces separadas através de pequenos blocos de layout.

Você também já sabe, que um componente nada mais é do que bits de código independentes e reutilizáveis, que funcionam isoladamente e retornam um código HTML, certo?

Se você concordou comigo, então creio que você já está pronto para criar seu primeiro componente 😄

Criando seu primeiro componente

Como de praxe, vamos iniciar criando um novo projeto em ReactJS:

npx create-react-app meu-primeiro-componente

Com seu projeto criado, não se esqueça de fazer aquela limpeza no código 😊

Como você já sabe, dentro da pasta src nós temos o App.js:

export default function App() {
 return (
 <div>Olá ReactJS!</div>
 );
}

Este arquivo por si só já é considerado um tipo de componente em ReactJS.

E apesar dele ser considerado um componente principal da nossa aplicação, ainda assim, ele é considerado um componente.

Mas para não embolar muito a sua cabeça neste início, vamos criar um outro componente do zero

Um componente nada mais é do que uma função em Javascript que é exportada usando o comando export ou export default. Onde dentro dessa função, obrigatoriamente é necessário o uso do comando return, que por sua vez é usado para retornar o código HTML daquele componente. Vejamos como isso acontence.

Passo 1) Dentro da pasta src, crie um novo arquivo chamado Nome.js:

Observação: Nos arquivos de componentes ReactJS, é uma prática comum usar a convenção de começar sempre com uma letra maiúscula.

Por exemplo, se o componente se chama "MeuComponente", o nome do arquivo será "MeuComponente.js"

Passo 2) Dentro do arquivo, basta criar a estrutura inicial do seu código, seguindo as regras que eu mencionei acima:

function Nome(){
 return(
 <div>Meu Nome é: Micilini Roll</div>
 )
}

export default Nome;

Como podemos ver no código acima, estamos criando uma função chamada Nome - que é o nome do meu componente -, e retornando um código HTML dentro da tag return.

Por fim, estamos exportando a função Nome que acabamos de criar usando o comando export default.

Legal, acabamos de criar um novo componente em ReactJS que mostra o nome de alguém, que no meu caso, mostra o nome do nosso portal 😋

Entretanto, um componente poderia ser um cabeçalho, um menu, um rodapé, um bloco de mensagem, um modal ou qualquer outra coisa que tenha por objetivo exportar um código HTML.

Veja um formato mais enxuto de criar um componente:

export default function Nome(){
 return(
 <div>Meu Nome é: Micilini Roll</div>
 )
}

Perfeito, agora que você tem seu primeiro componente criado, chegou o momento de aprendermos a importá-lo no App.js.

Usando seu primeiro componente

Dentro do App.js, que é a porta principal da sua aplicação, nos temos o seguinte código:

export default function App() {
 return (
 <div>Olá ReactJS!</div>
 );
}

Para importar o componente Nome que acabamos de criar, basta importar o arquivo fora da função App() usando o comando import ... from ...:

import Nome from './Nome.js';

Após isso, você deve fazer o uso do nome da função daquele componente recém importado dentro do return, onde o nome do componente se transforma em uma tag HTML:

<Nome />

Veja como ficou o arquivo final (App.js):

import Nome from './Nome.js';

export default function App() {
 return (
 <div>
 Olá ReactJS!
 <Nome />
 </div>
 );
}

Rodando a sua aplicação no navegador (npm start), nós temos o seguinte resultado:

Isso significa que seu primeiro componente foi criado e foi implementado com sucesso, parábens 🥳

E se eu trocar a nomenclatura do App.js?

Se você é tão curiosos como eu sou, talvez tenha se perguntado: "Será que dá pra mudar o nome da minha aplicação principal?".

Pois pensa comigo, se o App.js é considerado um componente no ReactJS, e se ele segue a mesma estrutura do componente Nome que acabamos de criar, ao mesmo tempo que ele esta sendo importado como <App /> dentro do index.js, será que é possível mudar a sua nomenclatura?

Sim, é totalmente possível, vejamos como isso acontece:

Passo 1) Comece alterando a nomenclatura de App.js para Micilini.js:

Passo 2) Em seguida, você vai precisar alterar o nome da função de App() para Micilini():

import Nome from './Nome.js';

export default function Micilini() {
 return (
 <div>
 Olá ReactJS!
 <Nome />
 </div>
 );
}

Passo 3) Por fim, não se esqueça de mudar as implementações e importações que estão acontecendo dentro do index.js:

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import Micilini from './Micilini';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
 <React.StrictMode>
 <Micilini />
 </React.StrictMode>
);

E pronto, nós acabamos de mudar o nomenclatura da nossa aplicação inicial 😆

Mas porque você não deve fazer isso?

Embora seja tecnicamente possível renomear o arquivo App.js para outro nome, como é o caso do Micilini.js, não é uma prática recomendada. Isso ocorre por algumas razões:

Convenção e Consistência: A comunidade ReactJS geralmente segue uma série de convenções e padrões de nomenclatura para facilitar a compreensão e manutenção dos projetos. Manter o arquivo principal como App.js segue essa convenção comum e ajuda outros desenvolvedores a entenderem rapidamente onde está localizada a lógica principal da aplicação.

Facilidade de Localização: Ao trabalhar em uma equipe ou ao usar ferramentas de desenvolvimento, é útil quando os arquivos principais são facilmente identificáveis. Manter o nome App.js facilita a localização do componente raiz da aplicação.

Compatibilidade com Ferramentas e Scripts: Algumas ferramentas e scripts podem assumir que o arquivo principal da aplicação é chamado App.js. Renomear o arquivo pode causar conflitos com essas ferramentas e scripts e exigir ajustes adicionais.

Sendo assim, nunca mude a nomenclatura da sua aplicação principal.

Criando componentes dentro de funções anônimas (recomendável)

Desde a chegada dos React Hooks, a comunidade de desenvolvedores adotou uma nova maneira de se criar componentes,e isso é feito por meio do uso de funções anônimas dentro de constantes.

Logo no início desta lição, você aprendeu a criar componentes da seguinte forma:

function Nome(){
 return(
 <div>Meu Nome é: Micilini Roll</div>
 )
}

export default Nome;

Só que, a maioria das aplicações que estão sendo lançadas hoje, não estão mais sendo exportadas dentro de funções puras, mas sim dentro de constantes que executam funções anônimas, observe:

const Nome = () => {
 return(
 <div>Meu Nome é: Micilini Roll</div>
 )
}

export default Nome;

Ou caso você queira uma versão um pouco mais enxuta:

export default () => {
 return(
 <div>Meu Nome é: Micilini Roll</div>
 )
}

Há algumas razões pelas quais as pessoas estão optando por usar funções anônimas dentro de constantes para criar componentes em ReactJS:

Clareza e Concisão: O uso de funções anônimas dentro de constantes pode tornar o código mais conciso e legível, especialmente para componentes simples que não precisam de muito boilerplate.

Isso pode tornar o código mais fácil de entender para desenvolvedores que estão familiarizados com o JavaScript moderno.

Escopo: Colocar o componente em uma constante permite que ele seja definido em um escopo local, o que pode ajudar a evitar poluição do escopo global e a manter um código mais organizado.

Compatibilidade com Hooks: Muitos Hooks do React, como useState, useEffect e useContext (veremos o funcionamento deles em lições futuras), são comumente usados em componentes funcionais. Definir um componente como uma função anônima dentro de uma constante facilita o uso desses Hooks diretamente dentro do componente.

Sendo assim, sempre que for criar novos componentes, faça isso dentro de uma constante que executa uma função anônima 😁

"Eu preciso converter o código do App.js em uma função anônima também?".

Não, pois não é estritamente necessário que o App.js seja transformado em uma função anônima, no entanto, usar um componente de função é uma prática mais comum e moderna, especialmente para projetos mais recentes.

Sendo assim, não é necessário alterar a esturutra do App.js, pois ele já se encontra em um padrão comum que é amplamente utilizado em diversos projetos ReactJS.

O que são fragmentos no ReactJS?

Antes de responder essa pergunta, porque você não tenta remover aqueles encapsulamentos de <div></div> que existem tanto dentro dos arquivos App.js e Nome.js?

Toda a sua aplicação quebrou, não?

Isso aconteceu pois o ReactJS nos obrigado a encapsular todo o conteúdo HTML dentro de uma outra tag PAI antes de executar um return.

Essa tag costuma ser uma <div> quanto qualquer outro elemento como <aside>, <header>, <footer> e afins. Pois é dessa forma que o ReactJS reconhece que o conteúdo a seguir se trata de elementos HTML.

No contexto do ReactJS, um fragmento nada mais é do que uma forma abrevida de se inserir as tags de encapsulamento (<div></div>). Na qual você pode fazer o uso dos elementos <></>, o que representa uma forma mais abreviada de se encapsulá-los, observe:

const Nome = () => {
 return(
 <>
 Meu Nome é: Micilini Roll
 </>
 )
}

export default Nome;

Em vez de usar <div> ou qualquer outro elemento como container, você pode usar um fragmento vazio (<></>) para envolver os elementos HTML.

Vejamos um outro exemplo:

return (
 <>
 <h1>Título do Documento</h1>
 <p>Esta é uma informação relevante!</p>
 <p>Do Portal da Micilini!</p>
 </>
);

O código acima é equivalente a:

return (
 <div>
 <h1>Título do Documento</h1>
 <p>Esta é uma informação relevante!</p>
 <p>Do Portal da Micilini!</p>
 </div>
);

Usar um fragmento vazio (<></>) é útil quando você não quer adicionar elementos extras ao DOM, como é o caso de um <div> extra que vai ser inserida a cada importação de um componente, por exemplo.

JS vs JSX

Até o momento, nós aprendemos a criar nossos componentes usando a extensão .js, que nada mais é do que a representação de um arquivo Javascript.

Entretanto, a comunidade do ReactJS vem adotando e separando cada vez mais algumas convenções, de modo a distinguir o que vem a ser um arquivo de lógica (.js) e um arquivo que representa um componente (.jsx).

Tanto as extenções .js quanto .jsx são comumente usadas em projetos ReactJS para distinguir entre arquivos JavaScript padrão e arquivos que contêm JSX (JavaScript XML), uma extensão da sintaxe JavaScript usada para escrever componentes em React.

Sendo assim, no que diz a respeito aos arquivos .js,  eles são usados para armazenar qualquer código do Javascript que seja válido, e isso inclui a lógica de negócios, funções utilitárias, importações/exportações e entre outros.

Já os arquivos .jsx são arquivos que podem conter tanto código Javascript quanto códigos HTML.

JSX é uma extensão da sintaxe JavaScript que permite escrever marcação semelhante ao HTML dentro do JavaScript. Isso facilita a criação de componentes em ReactJS, pois permite a definição de interfaces de usuário de forma declarativa.

É importante ressaltar que os arquivos .jsx são compilados para Javascript (.js) antes de serem executados no navegador.

Escrever um componente em .js ou em .jsx, tem alguma diferença?

Não, pois não existe uma diferença técnica entre escrever um componente em um arquivo com a extensão .js e outro em um arquivo com a extensão .jsx, o que muda mesmo é a extensão do arquivo, somente isto.

A distinção se dá somente na convenção da nomenclatura que ajuda os desenvolvedores a identificarem quais arquivos são componentes (.jsx) daqueles que não são (.js).

Observação: o fato de usar tais nomenclaturas é uma questão de preferência pessoal ou de convenção da equipe. Isso significa que não há problema nenhum em continuar criando componentes usando a extensão .js (em vez de .jsx).

Altere a extensão dos seus componentes

Aqui nesta jornada, iremos adotar a convenção de arquivos .jsx para arquivos que representam componentes. Sendo assim, é recomendável que você altere a extensão do seu componente Nome.js para Nome.jsx. E não se esqueça de corrigir a extensão que está sendo importada dentro do App.js

"Preciso também alterar o nome de App.js para App.jsx?".

Não necessariamente, mas se você fizer essa alteração seu código vai continuar funcionando normalmente 😆

Aqui na nossa jornada, ao menos o arquivo App.js e index.js iremos mantêr-los com a extensão .js.

Declarando elementos HTML dentro do ReactJS

Quando declaramos elementos HTML dentro de uma aplicação em ReactJS, temos que estar atentos a alguns pontos, pois a forma de escrita acontece de forma um pouco diferente do que já estamos habituados em aplicações puras (HTML5).

No ReactJS as tags HTML assumem um outro nome, onde chamamos elas de JSX (ou JavaScript XML). Veremos nos tópicos abaixo alguns cuidados adicionais a serem considerados em relação ao seu uso.

class vs className

No HTML puro, quando nós queremos adicionar a propriedade class para posteriormente estilizarmos um elemento, nós fazemos isso dessa forma:

<div class="container"></div>
<input class="meu-campo" />
<section class="section-1"></section>

No JSX isso não funciona, pois o nome class é um nome reservado pelo sistema do Javascript para identificar classes.

Aqui nós fazemos o uso do atributo className da seguinte forma:

<div className="container"></div>
<input className="meu-campo" />
<section className="section-1"></section>

Vejamos um exemplo de um componente real:

const Header = () => {
 return(
 <header className="header-content">
 <p className="content-text">Bem vindo a Aplicação =)</p>
 </header>
 )
}

export default Header;

Note que estamos fazendo o uso do atributo className dentro do componente, que por sua vez é equivalente ao atributo class do HTML puro.

Estilos Inline

No HTML puro, quando você quer escrever folhas de estilos dentro de um elemento (css inline), você faz isso da seguinte forma:

<div className="container" style="color:red; background-color:#4rd789"></div>

<input class="meu-campo" style="margin-top:450px;" />

Se tratando do JSX, o uso do css inline funciona de uma forma um pouco diferente, onde precisamos abrir duas chaves da seguinte forma:

<div style={{ color: 'red' }}>

O uso de chaves dentro de um return, significa que estamos fazendo o uso de uma função (código Javascript) dentro do JSX.

No caso do exemplo acima, o estilo segue uma estrutura de chave e valor - assim como em qualquer objeto em Javascript -.

Só que tem um único porém, nem sempre o atributo que você deseja mudar, leva o mesmo de um atributo normal do CSS, por exemplo.

No CSS puro, usamos margin-top para dar um espaçamento no topo do elemento. Já no JSX, ele assume o nome de marginTop, observe:

<div style={{ marginTop: '35px' }}>

O mesmo esquema segue para o background-color, onde no JSX ficaria:

<div style={{ backgroundColor: 'yellow' }}>

A sintaxe segue a convenção camelCase, onde os hífens são removidos e a primeira letra de cada palavra subsequente é maiúscula. Por exemplo:

  • background-color se torna backgroundColor
  • font-size se torna fontSize
  • border-top se torna borderTop
  • E assim por diante...

Comentários nos códigos

Dentro do return, a única forma de se fazer comentários é por meio da abertura de tags do Javascript, observe:

<div>
 {/* Este é um comentário em JSX */}
 <p>Conteúdo do parágrafo</p>
</div>

Lembrando que o uso das tags HTML: <!-- isso é um comentários --> não funciona no JSX.

Atributos Personalizados

No HTML, podemos declarar atributos personalizados da seguinte forma:

<div data-custom></div>

<input data-micilini="dez" />

No JSX para se manter conformidade com as especificações do HTML5 e evitar colisões com futuras adições ao HTML padrão, o esquema de declaração segue o mesmo, observe:

return (
 <div>
 {/* Atributo personalizado sem valor */}
 <p data-custom>Atributo personalizado sem valor</p>

 {/* Atributo personalizado com valor */}
 <p data-custom-valor="123">Atributo personalizado com valor</p>
 </div>
);

Uso de Eventos

No HTML, nós podemos fazer o uso de alguns eventos como é caso do onclick, onchange, onsubmit e etc, da seguinte forma:

<!-- Evento de clique -->
<button onclick="alert('Clicou no botão!')">Clique Aqui</button>

<!-- Evento de mudança de valor -->
<input type="text" onchange="console.log('Valor alterado:', this.value)">

<!-- Evento de envio de formulário -->
<form onsubmit="event.preventDefault(); console.log('Formulário enviado!')">
 <input type="text" name="nome">
 <button type="submit">Enviar</button>
</form>

Já no JSX, usamos o camelCase em vez de letras minúsculas. Por exemplo, onclick se torna onClick, onchange se torna onChange, etc.

return (
 <div>
 {/* Evento de clique */}
 <button onClick={handleClick}>Clique Aqui</button>

 {/* Evento de mudança de valor */}
 <input type="text" onChange={handleChange} />

 {/* Evento de envio de formulário */}
 <form onSubmit={handleSubmit}>
 <input type="text" name="nome" />
 <button type="submit">Enviar</button>
 </form>
 </div>
 );

Lembrando que dentro das chaves, informamos o nome das funções responsável por executar ou receber os eventos (veremos o funcionamento disso mais tarde).

Elementos vazios

No HTML, nós temos alguns elementos vazios como: <br>, <hr>, <input>, <img> e entre outros.

No JSX, esses elementos precisam ser fechados com a barra invertida, por exemplo:

return(
 <br />
 <hr />
 <input />
 <img />
)

O atributo FOR

No HTML podemos fazer o uso do atributo for atrelado a um <label> da seguinte forma:

<label for="campo-nome">Meu Nome</label>

Mas como você já deve saber, esse atributo também é de uso exclusivo do Javascript onde representa uma estrutura de laço (loop).

No JSX, fazemos o uso do atributo htmlFor, da seguinte forma:

return (
 <div>
 <label htmlFor="campoInput">Nome:</label>
 <input id="campoInput" type="text" />
 </div>
)

Lembrando que essas diferenças são necessárias para garantir a integração correta entre o JSX (JavaScript XML) e o JavaScript, já que o JSX é uma extensão de sintaxe do JavaScript usada pelo ReactJS para descrever a interface do usuário.

Importando estilos CSS para dentro do seu componente

No ReactJS, os estilos ligados ao seu componente devem existir dentro da pasta pasta onde o arquivo principal do seu componente se encontra.

Por exemplo, supondo que queremos criar uma folha de estilo para o nosso componente chamado Nome, como ele (ainda) se encontra solto dentro da pasta src, podemos criar um novo arquivo chamado nome.css:

Onde dentro dele, podemos declarar algumas propriedades:

header{
 background-color: blue;
 color:white;
}

Para importar o arquivo css dentro do componente Nome.jsx é simples, observe:

import './nome.css';

const Nome = () => {
 return(
 <header>
 Meu Nome é: Micilini Roll
 </header>
 )
}

export default Nome;

Veja que importei o arquivo de forma pura usando a tag import, e também informando o caminho especificado.

Importando imagens para dentro do seu componente

No JSX, a importação de imagens para dentro de componentes, pode ocorrer de duas formas diferentes.

A primeira delas envolve fazer upload da foto para a pasta src, e fazer o uso do import da seguinte forma:

import './nome.css';
import fotoPraia from './foto-praia.jpg';

const Nome = () => {
 return(
 <header>
 Meu Nome é: Micilini Roll <br />
 <img className="img" src={fotoPraia} alt="Foto da Praia" />
 </header>
 )
}

export default Nome;

Uma outra maneira é realizar um require diretamente no src, observe:

import './nome.css';

const Nome = () => {
 return(
 <header>
 Meu Nome é: Micilini Roll <br />
 <img className="img" src={require('./foto-praia.jpg')} alt="Foto da Praia" />
 </header>
 )
}

export default Nome;

Observe como ficou o resultado final:

Importando imagens estáticas dentro de um componente

Supondo que agora que a imagem da praia exista dentro da pasta public > assets > img. Basta que você faça a importação normalmente sem fazer o uso do require ou import:

<div>
 <img src="/assets/img/foto-praia.jpg" alt="Foto da praia" />
</div>

Quantos returns podemos ter dentro de um componente?

Anteriormente, você viu que um componente deve possuir ao menos um comando return para retornar os elementos em JSX.

Mas será que é possível ter mais de um único return por componente? Será que isso é considerado uma boa prática?

A resposta é sim, você pode ter mais de um único return dentro de um componente em ReactJS, uma vez que um componente nada mais é do que apenas uma função em Javascript.

return(
<>Retorno 1</>
)

return(
<>Retorno 2</>
)

return(
<>Retorno 3</>
)

É claro que no exemplo acima, o primeiro return será sempre executado primeiro, ignorando todos os outros dois.

Em lições futuras, você verá multiplos tipos de retornos que podem ser acionados por diferentes lógicas dentro de um único componente 🤓

Podemos ter mais de um único componente dentro de um mesmo arquivo?

Nesse momento, talvez você esteja se perguntando: "Será que é possível ter mais um único componente declarado dentro de um mesmo arquivo?".

Sim, isso é totalmente possível de ser feito (apesar de não ser considerado uma boa prática.).

Para isso vamos criar um novo componente chamado MaisDeUmComponente.jsx de modo a declarar dois componentes dentro de um único arquivo:

const ComponenteUm = () => {
 return(
 <>Primeiro Componente!</>
 )
}

const ComponenteDois = () => {
 return(
 <>Segundo Componente!</>
 )
}

export { ComponenteUm, ComponenteDois };

Perceba que mais de um componente foi declarado e exportado dentro de um objeto ({ ComponenteUm, ComponenteDois })

Caso desejar, você pode fazer uma exportação mais simplificada, observe:

export const ComponenteUm = () => {
 return (
 <>Primeiro Componente!</>
 );
};

export const ComponenteDois = () => {
 return (
 <>Segundo Componente!</>
 );
};

Para usar esses componentes, você pode importá-los da seguinte forma no App.js:

import { ComponenteUm, ComponenteDois } from './MaisDeUmComponente.jsx'; 

export default function App() {
 return (
 <div>
 <ComponenteUm />
 <ComponenteDois />
 </div>
 );
}

Perceba que estamos importando ambos componentes exportados via objeto   ({ ComponenteUm, ComponenteDois })  dentro de App.js e usando eles dentro do mesmo return.

Componente dentro de componente

Você não precisa ficar declarando todos os seus componentes dentro do App.js, sabia disso?

Existem componentes que podem (e devem) existir dentro de outros. E no ReactJS isso é totalmente possível de ser feito.

Vamos pegar como exemplo o cabeçalho do Portal da Micilini:

Neste exemplo, o cabeçalho vai ser um componente, que por sua vez vai importar outro componente chamado Logo, que contém o logo da nossa plataforma.

Cabecalho.jsx:

import './cabecalho.css';
import Logo from './Logo.jsx';

const Cabecalho = () => {
 return(
 <header className="cabecalho">
 <Logo />
 </header>
 )
}

export default Cabecalho;

Note que estamos importando um componente chamado Logo para dentro do compomente Cabecalho.

cabecalho.css:

.cabecalho{
 background-color: #21262C;
 color:white;
 width: 100%;
 height: 81px;
 display: flex;
 align-items: center;
}

Logo.jsx:

import './cabecalho.css';
import LogoMicilini from './logo-micilini.svg';

const Logo = () => {
 return(
 <>
 <img src={LogoMicilini} alt="Logo Micilini" style={{ width: 'auto', height: '52px' }} />
 </>
 )
}

export default Logo;

App.js:

import Cabecalho from './Cabecalho.jsx';

export default function App() {
 return (
 <div>
 <Cabecalho />
 </div>
 );
}

Observe como ficou o resultado final:

"Quantos componentes aninhados podem existir dentro de outros?".

Não há um limite certo de quantos componentes são permitidos. Pois já vi projetos que usaram mais de 4 componentes aninhados em conjunto com o padrão Atomic Design.

Chamando o mesmo componente por diversas vezes

No ReactJS você não fica apenas limitado a chamar um determinado componente apenas uma única vez dentro da sua aplicação, visto que você pode chama-lo quantas vezes desejar, observe:

import ComponneteUm from '../ComponenteUm';

...

return(
 <>
 <ComponenteUm />
 <ComponenteUm />
 <ComponenteUm />
 </>
)

Observe que no comando acima, estou chamando diversas vezes o ComponenteUm onde foi preciso importá-lo apenas uma vez no projeto inteiro.

Return de uma linha

Até o momento você aprendeu a usar o comando return em conjunto com os parêntesis () da seguinte forma:

return(
 <div>
 </div>
)

Mas você sabia que também é possível usar o return com apenas uma única linha de código HTML? Não? Vejamos como isso pode ser feito:

return <p>Olá ReactJS</p>

Isso é ótimo quando o nosso componente deve retornar poucas linhas de código HTML.

Portanto usando o return() para retornar códigos HTML que possuem mais de uma linha, já o return (sem os parêntesis) é usado apenas para retornar códigos HTML de uma única linha.

Organizando seus componentes em pastas

Agora chegou um dos momentos mais importantes na nossa jornada, onde servirá como um divisor de águas na sua carreira de desenvolvedor 😎

Até agora você aprendeu a criar seus componentes, arquivos css e também importar imagens de maneira solta dentro da pasta src.

Onde no momento todos os nossos arquivos se encontram bagunçados e mal organizados dentro daquela pasta 😱

A organização de arquivos em ReactJS pode (e deve) seguir um padrão de design chamado "Organização por Funcionalidade" ou "Organização por Característica".

Que visa agrupar os arquivos e pastas com base nas funcionalidades ou características da aplicação. Isso ajuda a manter a estrutura do projeto coesa e facilita a localização de arquivos relacionados quando você está trabalhando em uma determinada parte da aplicação.

A ideia é que os arquivos responsáveis por componentes, estilos, testes e afins, estejam agrupados em suas respectivas pastas específicas, o que torna a navegação e a manutenção do código mais intuitivas.

Agora chega de conversa e vamos aprender na prática como isso funciona 😎

Divisão em Componentes

Todos os arquivos .jsx, que representam componentes dentro do ReactJS devem existir dentro de uma pasta chamada components que por sua vez deve existir dentro da pasta src.

Além disso, cada componente deve existir dentro de uma pasta única que o identifique dentro de components. Por exemplo:

/src
 /components
 /ComponenteUm
 - ComponenteUm.jsx
 - ComponenteUm.css
 /ComponenteDois
 - ComponenteDois.jsx
 - ComponenteDois.css
 /Nome
 - Nome.jsx
 - nome.css
 /Cabecalho
 - Cabecalho.jsx
 - cabecalho.css
 /Logo
 - Logo.jsx
 - logo.css
 - logo-micilini.svg
 App.js
 App.css
 index.js
 index.css

Veja que foi criado uma pasta components dentro de src, onde ali dentro existem varias subpastas que sempre começam com o nome do componente (ComponenteUm, ComponenteDois, Nome, Cabecalho...).

Note também que dentro das pasta que identificam os componentes, temos os arquivos .jsx, .css e arquivos de imagens (.svg).

Já os arquivos App.js, App.css, index.js e index.css não precisam estar dentro de uma pasta específica, pois eles representam arquivos essenciais para a estrutura básica de um projeto ReactJS.

Caso um componente faça o uso de mais de uma única imagem, ou quem sabe um vídeo ou qualquer outro arquivos específico, e que é usado exclusivamente por aquele componente, estes arquivos devem existir dentro da pasta do componente.

Por exemplo, supondo que dentro do cabecalho eu tenha dois arquivos css (cabecalho.css e responsive-cabecalho.css) e mais 3 arquivos de imagens (logo.svg, whatsapp.png e info.svg), nesse caso, a estruturação estaria disposta da seguinte forma:

/src
 /components
 /Cabecalho
 - Cabecalho.jsx
 - cabecalho.css
 - cabecalho-responsive.css
 - logo.svg
 - whatsapp.png
 - info.svg

Para importar esses componentes basta fazer o import da seguinte forma:

import ComponenteUm from './components/ComponenteUm/ComponenteUm.jsx';

Simplificando o nome dos componentes em pastas organizadas

Existe uma forma mais simplificada e bastante utilizada por desenvolvedores ReactJS, que nos permite simplificar a chamada e também a inclusão dos nossos componentes em outros componentes.

Para isso voce vai precisar renomear o arquivo JSX que identifica o componente para index.jsx, por exemplo:

  • ComponenteUm.jsx fica como index.jsx
  • ComponenteDois.jsx fica como index.jsx
  • Nome.jsx fica como index.jsx
  • Cabecalho.jsx fica como index.jsx
  • E todo arquivo que representa um componente se transforma em index.jsx

Veja como ficaria a estrutura de arquivos:

/src
 /components
 /ComponenteUm
 - index.jsx
 - ComponenteUm.css
 /ComponenteDois
 - index.jsx
 - ComponenteDois.css
 /Nome
 - index.jsx
 - nome.css
 /Cabecalho
 - index.jsx
 - cabecalho.css
 /Logo
 - index.jsx
 - logo.css
 - logo-micilini.svg

Para importar, você não precisa informar mais o index.jsx no final do comando import, bastando apenas declará-los dessa maneira:

import ComponenteUm from './components/ComponenteUm';

O ReactJS se encarrega de buscar manualmente o arquivo index.jsx de maneira automática.

Observação: Não é porque o nome do arquivo se tornou index.jsx que a declaração do componente deverá ser Index. Você deve continuar mantendo o nome dos componentes como estávamos fazendo anteriormente, por exemplo:

src > components > Nome > index.jsx:

import './nome.css';
import fotoPraia from './foto-praia.jpg';

const Nome = () => {
 return(
 <header>
 Meu Nome é: Micilini Roll <br />
 <img className="img" src={fotoPraia} alt="Foto da Praia" />
 </header>
 )
}

export default Nome;

Containers (ou Páginas)

Apesar de não termos entrado neste assunto ainda, uma aplicação feita em ReactJS, precisa conter páginas.

No momento, você aprendeu que os componentes são apenas blocos de layout que quando juntos forma algo maior, como por exemplo:

  • Uma página de Login (que importa os componentes de cabeçalho, formulário, rodapé)
  • A página inicial da sua aplicação (que também importa os componentes da página de Login e mais alguns outros)
  • Uma página de edição de produtos e etc.

Nesse caso, precisamos criar de forma separada os arquivos que vão representar essas páginas, e que ao mesmo tempo não podem ser considerados "componentes".

Para isso, você deve criar uma nova pasta chamada containers ou pages dentro de src. Onde dentro dela você deve agrupar os arquivos JSX que representram essas páginas.

/src
 /containers
 /PaginaPrincipal
 - PaginaPrincipal.jsx
 - PaginaPrincipal.css
 /Login
 - Login.jsx
 - login.css
 /Dashboard
 - Dashboard.jsx
 - dashboard.css

Exemplo de estrutura onde a pasta principal se chama pages:

/src
 /pages
 /PaginaPrincipal
 - PaginaPrincipal.jsx
 - PaginaPrincipal.css
 /Login
 - Login.jsx
 - login.css
 /Dashboard
 - Dashboard.jsx
 - dashboard.css

Seguindo o exemplo dos componentes com nomes simplificados, podemos aplicar a mesma lógica aqui também:

/src
 /pages
 /PaginaPrincipal
 - index.jsx
 - PaginaPrincipal.css
 /Login
 - index.jsx
 - login.css
 /Dashboard
 - index.jsx
 - dashboard.css

A importação desses arquivos seguem a mesma estrutura vista anteriormente:

import Login from './pages/Login';

ou caso você não tenha mudado o nome do componente para index.jsx

import Login from './pages/Login/Login.jsx';

Serviços e Utilitários

Se você tiver lógica que não pertence diretamente a um componente, como funções de utilitário ou chamadas de API, pode ser útil agrupá-las em uma pasta de serviços ou utilitários.

Para isso criamos uma pasta chamada services dentro de src, onde costumamos agrupar toda a parte lógica do front-end da nossa aplicação:

/src
 /services
 - api.js
 - auth.js

Como esses arquivos não são componentes, o ideal é usar a extensão .js.

Para importá-los você pode fazer da seguinte forma:

import Api from './services/api.js';

Recursos Estáticos

Se você tiver arquivos estáticos, como imagens ou arquivos de dados, você pode colocá-los em uma pasta separada.

Para isso você pode criar uma pasta chamada assets dentro de src:

/src
 /assets
 /images
 - imagem1.png
 - imagem2.png

Para importá-los, você pode fazer isso da seguinte forma:

import imagem1 from './assets/images/imagem1.png';

Configurações

Se houver arquivos de configuração, como variáveis de ambiente ou configurações globais, você pode colocá-los em uma pasta de configuração.

Para isso você precisa criar uma pasta chamada config dentro da pasta src:

/src
 /config
 - config.js

Para importar basta seguir a mesma lógica dos outros:

import config from './config/config.js'

Como se trata de arquivo de lógica, o ideal é manter a extensão .js.

Rotas

Apesar de não termos entrado na lição que fala sobre rotas, é importante você saber que as rotas da sua aplicação também deve estar organizadas em um arquivo separado.

Para isso, você pode criar uma pasta chamada routes dentro de src:

/src
 /routes
 - AppRouter.js

Para importar basta seguir a mesma lógica dos outros:

import AppRouter from './routes/AppRouter.js'

Testes

No caso dos testes da sua aplicação,  pode ser útil colocá-los em uma pasta separada também.

Para isso você deve criar uma pasta chamada tests dentro de src, onde contém os testes que estão relacionados com todos os componentes e services:

/src
 /tests
 /components
 - ComponenteUm.test.js
 - ComponenteDois.test.js
 /services
 - api.test.js

Lembrando que os testes não são importados em outros arquivos, mas sim executados por outras aplicações externas.

Criando um componente do jeito certo!

De forma a compilar todos os conhecimentos adquiridos aqui, chegou a hora de te ensinar a criar um componente do jeito certo 😉

Para começar vamos criar um novo projeto chamado estrutura-organizada:

npx create-react-app estrutura-organizada

Em seguida, vamos fazer aquela limpeza de código.

Após isso, vamos criar a nossa estrutura inicial seguindo o padrão de organização por funcionalidade:

Feito isso, vamos criar o nosso primeiro componente chamado Cabecalho, para isso você vai precisar criar uma nova pasta chamada Cabecalho dentro de components, e mais dois arquivos chamados de index.jsx e cabecalho.css.

index.jsx:

import './cabecalho.css';
import Logo from '../Logo';

const Cabecalho = () => {
 return(
 <header className="cabecalho">
 <Logo />
 </header>
 )
}

export default Cabecalho;

cabecalho.css:

.cabecalho{
 background-color: #21262C;
 color:white;
 width: 100%;
 height: 81px;
 display: flex;
 align-items: center;
}

Em seguida precisamos criar o nosso componente que representa o Logo, para isso vamos criar mais uma pasta chamada Logo dentro da pasta components dessa forma:

index.jsx:

import LogoMicilini from '../../assets/logo-micilini.svg';

const Logo = () => {
 return(
 <>
 <img src={LogoMicilini} alt="Logo Micilini" style={{ width: 'auto', height: '52px' }} />
 </>
 )
}

export default Logo;

"Cade o logo.css?".

É importante ressaltar que quando um componente não precisa de uma folha de estilo, não se faz necessária a criação de uma.

Lembrando que existe um arquivo dentro da pasta assets chamado de logo-micilini.svg:

Em seguida, precisamos criar uma página inicial para a nossa aplicação. Para isso vamos criar uma nova pasta chamada Home dentro da pasta pages.

index.jsx:

import './home.css';
import Cabecalho from '../../components/Cabecalho';

const Home = () => {
 return(
 <div className="container">
 <Cabecalho />
 <p>Seja bem vindo a Micilini!</p>
 </div>
 )
}

export default Home;

home.css:

.container{
 height: 100vh;
 background-color: #19191B;
}

.container p{
 color:white;
 font-size: 18px;
 margin-top:40px;
 width: 100%;
 height: auto;
 text-align: center;
}

Por fim, basta chamarmos a nossa página Home dentro do App.js da seguinte forma:

import Home from './pages/Home';

export default function App() {
 return(
 <>
 <Home />
 </>
 )
}

Veja como ficou o resultado final:

Arquivos da Lição

Nesta lição eu separei em dois diretórios diferentes os conteúdos que foram mostrados aqui:

Conclusão

Ufa! Creio que já deu para absorver bastante conteúdo em uma única lição, não é mesmo?

Apesar disso, ainda estamos longe de parar de falar sobre os componentes em ReactJS.

Então... te espero na próxima lição 🤩