Trabalhando com Componentização no React + Typescript.
E aí, amigos! Tudo bem? Hoje vou escrever um pouco sobre componentização dentro do React, utilizando o Typescript, juntamente.
Pensamos assim: Um bom momento para se utilizar componentes é quando vamos utilizar algum botão / input e outros várias vezes na nossa aplicação, quando o design é o mesmo. Esse é o momento perfeito para se usufruir da componentização.
O projeto que vamos aplicar + configurações (quickly).
Vamos criar uma página simples, como se fosse uma página de cadastro, certo? Nela vamos ter uma logo, inputs , buttons + icons =)
Eu utilizo o yarn para criar meus projetos, mas se você usa npm é de boas também, para criar meu projeto com o template typescript eu rodo no terminal:
yarn create react-app components-example --template typescript
Com o projeto já criado e aberto no vscode (no meu caso), eu costumo fazer a seguinte limpeza:
Dentro de src eu deixo apenas 3 arquivos: O index.tsx, app.tsx e react-app-env.ts, ficando assim:
Agora, dentro de src crie uma pastinha chamada pages e dentro dela uma pasta chamada signin com um index.tsx =)
Bom, vamos precisar de duas libs na nossa empreitada, o styled-components e o react-icons, para isso é só jogar no terminal os comandinhos:
yarn add styled-components or npm i .....
yarn add react-icons or ...
Uma coisa importante, estamos trabalhando com Typescript, então temos que nos lembrar de adicionar a tipagem, o styled-components não vem com os tipos por padrão, então precisamos instalar os types para a nossa IDE ter acesso ao IntelliSense, certinho? No terminal é só jogar o comando:
yarn add @types/styled-components -D
Porque o -D? Simples, pois ele necessita ser instalado em modo de desenvolvimento, pois quando nossa aplicação for para produção o código vai ser convertido em JS e não em TS, sacou?
Dentro da nossa pasta de signin crie um arquivo de styles.ts, o que temos agora é isso:
Ah: Rodem o projeto, coisa que eu esqueci de falar antes, bom, com o yarn start or npm start.
Não vou entrar em muitos detalhes do html + css, ok? Nosso foco é outro, então os estilos iniciais do nosso index.tsx ficará assim:
Como não temos nada no css, ele apenas exportou o nosso Container e o Content.
Para podermos ver o resultado do que fizemos até agora, temos que ir lá no nosso app.tsx e importar o Signin, belê? Ficando assim:
Quando olharmos no nosso navegador vamos ter isso aqui:
Let’s apply some design into this page:
Como resultado teremos:
Daora, né? Agora vamos por a mão na massa e ir mais a fundo.
Preparando nossos components e fazendo as passagens:
Dentro da nossa pasta src e crie uma pasta chamada Components, dentro dela crie mais uma pasta chamada Input . Uma dica rápida é: Pra criar a pasta e o arquivo junto é só digitar Input/index.tsx ou js. Vai criar os dois ao mesmo tempo.
Vamos começar pelo nosso Input!
Quando falei em passagem ali no título me refiro a passagem de props que os nossos componentes vão receber, então, na nossa page de Signin nós vamos importar nossos dois componentes e vamos substituir o input por Input, ficando assim:
Porém vamos receber um erro, pois não informamos ainda quais são as propriedades que o nosso input pode receber.
Agora vai ficar divertido, bora.
O nosso input pode receber todas as propriedades comuns de um input, certo? Tendo isso em mente, vamos criar uma interface para as props do input, que vai ficar assim:
Porém temos um problema. Nós queremos acessar todas as propriedades possíveis de um input, então devemos utilizar o InputHTMLAttributes, porque aí sim vamos conseguir ter acesso as propriedades, o que vamos fazer é utilizar o extends dentro da nossa interface. Pois simplesmente iremos ter:
Agora precisamos informar ao nosso input as Props, ficando assim:
Muito simples, né? Simplesmente informarmos ao nosso input que queremos repassar as props, usamos o spread operator para pegar todas as propriedades que ele pode receber.
Agora vamos voltar a nossa page de Sigin e vamos repassar o a prop “name” para o nosso input, ficando assim:
Salvando isso tudo estará funcionando normalmente, exceto pelo fato que nossos inputs ficaram um tanto grudados um no outro, mas calma, que vamos resolver isso mais pra frente.
(Sei que o post vai ficar um pouco grande, até peço desculpas por não conseguir reduzir, porém penso que preciso dar uma passada por cada coisa ao invés de pular de um galho para o outro sem dar explicação).
2 Coisas que é legal saber:
- Sempre importe os estilos antes das interfaces, caso não, vai dar ruim.
- Caso você use lint no projeto, procure checar os erros antes de sair fazendo alterações, lembrem, estamos usando typescript;
Colocando os nossos icons dentro do Input
Aqui a coisa fica um pouco mais complexa, mas isso é uma constante na carreira de todos nós, sem pavor, vamos lá. Então a primeira coisa que vamos fazer é passar os icons dentro dos inputs, certinho? Na nossa única page vamos importar o React Icons e fazer as devidas importações, no meu caso vai ficar assim ó:
Nada horrível, né? Nessa altura você já deve imaginar o que a gente tem de fazer, penso. Se não sabe, devemos informar para o nosso input que queremos receber icons dentro do nosso input, então vamos fazer isso.
No nosso componente de icon vamos ter o seguinte código:
Vamos entender o que foi feito aqui.
Vejamos, como de praxe colocamos lá na nossa interface que vamos receber mais uma prop, ok? Desta vez é um caso à parte, porque estamos recebendo um Icon, não pode passar o icon ali como uma string ou boolean e etc, para isso nós utilizamos o React.ComponentType, lembre disso: Toda santa vez que você quiser receber um componente como propriedade, utilize-o. Vamos seguir aqui.
Antes do …rest, nós tínhamos props, mas simplesmente substituímos para …rest, passando o spread e pegando tudo o que há dentro dele, nada terrível.
Uma vez Componente, sempre Componente.
Se você já tem alguma experiência com React, já deve ter se ligado de uma coisa, o nosso icon é um Componente, depois de salvarmos o que fizemos até aqui vamos ver que os icons não apareceram, pq? Como estamos lidando com um componente precisamos chamar ele na nossa div como um componente.
Para isso, nas nossas props ,onde temos o nosso icon, vamos sobrescrever o icon para icon:Icon. Simplesmente porque o React não vai entender como um componente se colocarmos dentro da div algo como <icon />, sacou? O resultado vai ser:
Salvando isso vamos ver que…
Uhul! Tá lá os icons! Agora vamos dar o poder de receber as propriedades que um icon pode ter para o nosso amigo.
Isso é bem simples na verdade, dentro do pacote dos react-icons nós temos um cara chamado IconBaseProps. Nós vamos importar ele e colocar lá na nossa interface, estendendo o icon, ficando assim:
Tendo importado o IconBasesProps temos acesso a todas propriedades do icon, como size, color e por aí vai.
Uma coisa que devemos pensar é que nem todo input carece de ter um icon, então a solução é fazer um render condicional, nisso nosso código vai ficar assim:
Lá nossa interface colocamos um sinal de interrogação e fizemos um render condicional, caso exista icon ele vai executar. Salvando tudo o que fizemos até aqui, vamos ter o resultado:
Colocando o icon dentro do input + final
Agora chegamos na parte final! Mas temos que fazer alguns ajustes ainda. Primeiro que os icons estão fora do input, como resolvemos isso? Podemos simplesmente tirar o css que fizemos na nossa página de Signin e colocar dentro do do component de Input. Para isso vamos importar o styled-componentes.
Simples. Onde antes era <div> agora é container, vamos lá nossos estilos da página de Signin e vamos tirar alguns estilos de lá e colocamos no container que criamos, vai ficar assim:
Então só retiramos dos estilos do Signin a parte do Input, só tirem ela. Ao salvarmos tudo o que fizemos vamos ter o seguinte resultado:
Ainda não é o que queremos. Porém vamos fazer o seguinte, ao invés de passar os estilos dentro do input, vamos colocar ele dentro do Container. Ficando assim:
Veja, tiramos os estilos da tag input e colocamos no Container, nisso o nosso icon vai parar dentro do input, certo? O resultado vai ser esse aqui:
Dá entender que o icon ficou dentro do input, né? Porém não, o input é essa parte branquinha, então vamos fazer um hackezinho maneiro aqui pra ajeitar isso, simplesmente passando background transparent e border: 0 para o nosso input e aí o nosso resultado vai ser esse aqui:
O resultado vai ser:
Ohhh tamo perto. Agora vamos passar um display flex para o flex ficar em row e um align-items center para centralizar o todo pra nós:
Resultado:
Vamos dar uma distanciada do icon para o nosso texto, simplesmente passando uma margin diretamente no icon, através da chamada svg, vejamos:
O resultado vai ser:
Lindo! Agora pra finalizar, sério mesmo:
Os inputs estão grudados um n’outro, precisamos resolver isso. É bem simples, vejamos que temos & + input uma margin-top de 8px, mas agora não é mais input, é uma div. Então é mudarmos para & + div e o resultado vai ser:
O flex:1 significa que o nosso input vai ocupar todo espaço possível. Salvando todo o que fizemos vamos ter o resultado esperado:
Aeeee! Finalizado!!! Agora que temos nosso componente, podemos simplesmente importar ele em qualquer página que a gente quiser, se agora você criar uma página de Signup, é só importar input e passar as propriedades que você quiser, sem se preocupar com os estilos e tudo mais.
Era isso, gente. Uma coisa que eu acho importante falar: Nem sempre criar um hiper componente é uma boa ideia, tem casos e casos, nesse caso cai feito luva, mas tem vezes que a aplicação cresce tanto que fica terrível ficar criando coisas dentro de um componente, há um limite, pensem sobre.
Link importantes:
Fiquem em casa e protejam os seus, um abraço e vamos juntos até o próximo nível.