DEV Community

Cover image for React - Como iniciar um projeto?
Bruno Felipe
Bruno Felipe

Posted on

React - Como iniciar um projeto?

🔰 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

Page

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

... para entrar na pasta do projeto, e...

npm start
Enter fullscreen mode Exit fullscreen mode

... para abrir no seu browser padrão.

Você deve ver uma tela como essa:
Print #1

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
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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')
);
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

Se você não cancelou o npm start, basta acessar no seu browser http://localhost:3000 e verá algo como isso:

Print #2

⚠️ 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
Enter fullscreen mode Exit fullscreen mode

E importaremos no App.tsx:

import Header from "./components/Header";

function App() {
  return (
    <div>
      <Header />
    </div>
  );
}

export default App;

Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

E no App.tsx:

import Header from "./components/Header";

function App() {
  return (
    <div>
      <Header />
      <Header title="Titulo Novo" />
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

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} />
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode
// 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>
  )
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
import Header from "./components/Header";
import TransactionList from "./components/TransactionList";

function App() {
  return (
    <>
      <Header />
      <TransactionList />
    </>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

📌 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
Enter fullscreen mode Exit fullscreen mode

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:

Print #3

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
Enter fullscreen mode Exit fullscreen mode

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)
 }
Enter fullscreen mode Exit fullscreen mode

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.

Print #4

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
Enter fullscreen mode Exit fullscreen mode

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'])
}
Enter fullscreen mode Exit fullscreen mode

Assim deixamos a cargo do React alterar o estado, e consequentemente alterar a tela.

Print #5

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)