🔰 Introdução
Nesse post vamos criar nossa primeira aplicação React utilizando o template Create-React-App e Typescript, um superset de Javascript que adiciona tipagem e várias outra funcionalidades mais atuais da linguagem.
📝 Pré-requisitos
- Node.js instalado na sua versão LTS.
- VSCode ou qualquer outro editor de código da sua preferencia.
- Um browser qualquer.
⚠️ Esse tutorial foi desenvolvido utilizando o Linux, e é possível que algum comando talvez não funcione exatamente no Windows ou Mac. Nesses casos, Google é seu melhor amigo.
🔭 Conhecendo o projeto
Nós vamos criar um projeto chamado de GoFinances, um gerenciador de gastos. Nele vamos poder cadastrar saídas e entradas de dinheiro, além de informar a categoria desse valor.
Algo básico, mas um bom projeto para começar.
💻 Criando projeto com CRA
Primeiramente escolha a pasta onde você vai trabalhar no seu novo projeto e acesse ele pelo terminal. Se tiver instalado corretamente o Node, você terá acesso a um comando chamado npx
. Com ele é possível executar códigos externos sem a necessidade de baixá-los e instalá-los em nossa máquina.
O comando completo é:
npx create-react-app go-finances --template=typescript
O que significa cada parte desse comando:
-
npx
executa o comando. -
create-react-app
é pacote que será usado para criar o template da nossa aplicação. -
go-finances
é o nome do projeto. -
--template=typescript
é para sobrescrever o template padrão para o que utiliza o typescript.
Após rodar esse comando, o projeto e todas suas dependências começaram a serem baixadas, e assim que terminar, bastar rodar...
cd go-finances
... para entrar na pasta do projeto, e...
npm start
... para abrir no seu browser padrão.
Você deve ver uma tela como essa:
Abrindo o projeto no VSCode vamos encontrar uma estrutura como essa:
├── package.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
├── README.md
├── src
│ ├── App.css
│ ├── App.test.tsx
│ ├── App.tsx
│ ├── index.css
│ ├── index.tsx
│ ├── logo.svg
│ ├── react-app-env.d.ts
│ ├── reportWebVitals.ts
│ └── setupTests.ts
├── tsconfig.json
└── yarn.lock
Vamos começar a limpar essa estrutura. Na pasta public
vamos deixar apenas o index.html
e favicon.ico
. Dentro do index.html
vamos apagar tudo que não é necessário por agora deixando apenas:
<!DOCTYPE html>
<html lang="pt_BR">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Go Finances"
/>
<title>Go Finances</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
Tá vendo essa <div id="root"></div>
? É dentro dela que toda nossa aplicação vai ser renderizada pelo React. Então ela é bem importante. Não apaguem ela!
Na pasta src
, vamos deixar App.tsx
, index.tsx
e react-app-env.d.ts
por enquanto e mudando o conteúdo do index.tsx
para:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
Esse arquivo é a entrada da nossa aplicação. No fim do arquivo dá pra ver que a lib react-dom
renderiza o conteúdo do primeiro parâmetro na <div id="root"></div>
.
Agora o App.tsx
:
function App() {
return (
<div>
<header>
<p>
Edite <code>src/App.tsx</code> e salve para recarregar.
</p>
<a
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Aprenda React
</a>
</header>
</div>
);
}
export default App;
Se você não cancelou o npm start
, basta acessar no seu browser http://localhost:3000 e verá algo como isso:
⚠️ Vale ressaltar de que desde a versão 17 do React não é mais necessário importar o React em cada arquivo. Se você tiver trabalhando em um projeto em uma versão anterior, é necessário adicionar import React from 'react'
na primeira linha do App.tsx
. E não se esqueça do export default nome-do-componente
, sem ele o componente não poderá ser importado em outro arquivo.
📦 Componentização
Esse é o um dos mais importantes conceitos do React e você já está utilizando. Tudo na nossa aplicação é um componente. O arquivo App.tsx
é o componente principal dessa aplicação. O que define um componente para mim é: "Uma função que recebe parâmetros e retorna um conteúdo JSX".
Os parâmetros ficam para o próximo tópico, mas o que é JSX?
JSX é o HTML dentro do Javascript. No nosso caso usando Typescript os aquivos que são componentes tem terminação *.tsx
. Lembrando que todos componentes devem iniciar com letra maiúscula.
Todo componente pode ser importado e utilizado dentro de outro componente, ou até mesmo dentro um arquivo normal TS (ou JS).
Vamos criar o primeiro componente que será o header (cabeçalho). Primeiro, dentro da pasta src
, vamos criar uma pasta components
onde ficaram guardados todos nossos componentes. Criaremos um arquivo assim:
// components/Header.tsx
function Header() {
return (
<div>
<header>
<span>Go Finance</span>
<nav>
<a href="#">Listagem</a>
<a href="#">Cadastro</a>
</nav>
</header>
</div>
)
}
export default Header
E importaremos no App.tsx
:
import Header from "./components/Header";
function App() {
return (
<div>
<Header />
</div>
);
}
export default App;
Agora com esse componente de Header podemos reutilizá-lo em todas as telas, e se qualquer mudança for necessária basta alterar o componente e a mudança será refletida em todas as telas.
🔧 Propriedade
Como fazemos para alterar um componente sem ter que mudar o código? E se em cada tela diferente quiséssemos que o texto dentro do Header fosse diferente? É aí que entra as propriedades.
// components/Header.tsx
type HeaderProps = {
title?: string
}
function Header(props: HeaderProps) {
return (
<div>
<header>
<span>{props.title ?? 'Go Finances'}</span>
<nav>
<a href="#">Listagem</a>
<a href="#">Cadastro</a>
</nav>
</header>
</div>
)
}
export default Header
Todas as propriedades de um componente vem dentro do argumento props
. Já que estamos utilizando Typescript vamos tipar as propriedades com o tipo HeaderProps
indicando que o objeto props
tem um valor opcional title
que deve ser uma string
. Para adicionar o valor no JSX basta colocar a variável props.title
entre {}. Caso nada seja passado para essa propriedade o valor padrão é Go Finances.
Podemos melhorar esse código utilizando de desestruturação:
// components/Header.tsx
type HeaderProps = {
title?: string
}
function Header({ title = 'Go Finances' }: HeaderProps) {
return (
<div>
<header>
<span>{title}</span>
<nav>
<a href="#">Listagem</a>
<a href="#">Cadastro</a>
</nav>
</header>
</div>
)
}
export default Header
E no App.tsx
:
import Header from "./components/Header";
function App() {
return (
<div>
<Header />
<Header title="Titulo Novo" />
</div>
);
}
export default App;
Para passar um valor que não seja string utilizamos {}:
// number
<Component prop={1} />
// array
<Component prop={[1, 2, 3]} />
//object
<Component prop={{ a: 1, b: 2, c: 3 }} />
// true
<Component prop={true} />
or
<Component prop />
//false
<Component prop={false} />
Uma propriedade especial que o próprio React adiciona é o children
que nada mais é que o conteúdo de um componente.
Imagine que dentro do Header queremos passar também os links, como podemos fazer isso?
function App() {
return (
<div>
<Header>
<a href="/">Home</a>
<a href="/sobre">Sobre</a>
<a href="/login">Login</a>
</Header>
</div>
);
}
// components/Header.tsx
import { ReactNode } from "react"
type HeaderProps = {
children?: ReactNode
}
function Header({ children } : HeaderProps) {
return (
<div>
<header>
<span>Go Finances</span>
<nav>
{children}
</nav>
</header>
</div>
)
}
Vamos voltar o código para como estava no fim no tópico de Componentização.
💡 Estado e Imutabilidade
Vamos criar um novo componente para essa explicação e importar no App.tsx
para ver na tela:
// components/TransactionList.tsx
function TransactionList() {
return (
<div />
)
}
export default TransactionList
import Header from "./components/Header";
import TransactionList from "./components/TransactionList";
function App() {
return (
<>
<Header />
<TransactionList />
</>
);
}
export default App;
📌 O React não aceita que o return
tenha mais de um componente diretamente um abaixo do outro, por isso estamos utilizando o <></>
por volta dos dois.
Eles servem para agrupar os componentes sem ter que renderizar uma <div>
em volta por exemplo.
No componente TransactionList.tsx
vamos salvar uma lista fictícia de transações e tentar renderiza-las em uma <ul>
:
// components/TransactionList.tsx
function TransactionList() {
const transactions = [
'-R$ 100,00 - Compra de Alimentos - 22/11/2020',
'-R$50,00 - Gasolina - 20/12/2020',
'R$32,00 - Investimento - 22/12/2020'
];
return (
<ul>
{transactions.map((transaction, i) => (
<li key={i}>{transaction}</li>
))}
</ul>
)
}
export default TransactionList
Criamos inicialmente uma lista de strings que contém nossas transações. Depois retornamos no componente uma lista (<ul>
) que renderiza todos as transactions
através de um map
que retorna uma <li>
que tem como conteúdo cada item da nossa lista.
Há também a propriedade key
que recebe um valor único entre os elementos da lista. Como não temos essa valor ainda, vamos colocar o index de cada transação.
A documentação diz:
As chaves ajudam o React a identificar quais itens sofreram alterações, foram adicionados ou removidos.
A chave deve ser colocada no elemento mais "externo" do retorno do map
. Caso você não coloque aparecerá um erro como esse:
Vamos agora criar um botão para adicionar uma nova transação na lista.
// components/TransactionList.tsx
function TransactionList() {
const transactions = [
'-R$ 100,00 - Compra de Alimentos - 22/11/2020',
'-R$50,00 - Gasolina - 20/12/2020',
'R$32,00 - Investimento - 22/12/2020'
];
function handleAddTransaction() {
console.log('clicado')
}
return (
<>
<ul>
{transactions.map((transaction, i) => (
<li key={i}>{transaction}</li>
))}
</ul>
<button onClick={handleAddTransaction}>
Adicionar Transação
</button>
</>
)
}
export default TransactionList
Para adicionar uma função que é disparada ao clicar no botão, basta criar a função e adiciona-lá a propriedade onClick
. Teste no seu projeto e veja no console (ctrl + shift + i
) do browser se está funcionando.
Se mudarmos o código da função para adicionar uma nova transação na lista ficaria assim:
function handleAddTransaction() {
transactions.push('Nova transação')
console.log(transactions)
}
Porém se abrirmos nossa aplicação e clicarmos no botão veremos que a tela não é atualizada, mas no console aparece que a lista está recebendo novos items.
Isso acontece porque o React não sabe que deve atualizar a tela apenas de mudarmos o valor da variável transactions
. Temos que criar um estado que guardará a lista de transações. Para isso utilizaremos o hook useState.
// components/TransactionList.tsx
import { useState } from "react";
function TransactionList() {
const [transactions, setTransactions] = useState([
'-R$ 100,00 - Compra de Alimentos - 22/11/2020',
'-R$50,00 - Gasolina - 20/12/2020',
'R$32,00 - Investimento - 22/12/2020'
])
function handleAddTransaction() {
console.log(transactions)
}
return (
<>
<ul>
{transactions.map((transaction, i) => (
<li key={i}>{transaction}</li>
))}
</ul>
<button onClick={handleAddTransaction}>
Adicionar Transação
</button>
</>
)
}
export default TransactionList
O useState
retorna um array, sendo a primeira posição a valor real do estado e como segunda posição uma função utilizada para alterar esse estado.
Como parâmetro ele recebe o valor inicial do estado. No nosso caso são os valores das primeiras transações de teste.
Para alteramos o valor de transactions
passamos o novo valor para a função setTransactions
. Ai entra a imutabilidade. Não devemos alterar o valor do estado diretamente como fizemos anteriormente usando transactions.push('Nova transação')
. Devemos criar uma nova lista de transações que contenha os valores anterior da lista e adicionando o novo valor:
function handleAddTransaction() {
setTransactions([...transactions, 'Nova Transação'])
}
Assim deixamos a cargo do React alterar o estado, e consequentemente alterar a tela.
Utilizamos o useState
quando precisamos salvar um valor que será utilizado para alterar a tela ou algum componente. Poderia ser por exemplo o número de notificações não lidas pelo usuário, ou o número de likes em foto ou até a lista de comentários de uma postagem. Todos são valores que, se alterados, devem alterar o que o usuário vê.
😅 Só isso tudo?
É bastante coisa para aprender de uma vez. O que eu aconselho é entre esse e o próximo tutorial você teste algumas das suas ideias utilizando Componentização, Propriedade e Estado. Talvez criar um pequeno contador que diminui e aumente o valor recebido por propriedade... Bem são infinitas possibilidades.
Se for seguir meu conselho tente algo simples, nada de tentar começar com a próxima ideia revolucionaria de uma nova empresa do Elon Musk.
Bem... por enquanto, isso é tudo pessoal!
No próximo post vamos iniciar de verdade nosso projeto já estilizando a aplicação.
PS: Um agradecimento especial💜 ao pessoal da Rocketseat🚀 pelo conteúdo de qualidade em React.
Top comments (0)