Domine o Roteamento React: Guia Completo com React Router DOM

Em qualquer aplicação React de complexidade considerável, é imperativo estruturá-la em múltiplas páginas. Para atingir este objetivo, torna-se indispensável a implementação de um sistema de roteamento.

Este tópico pode gerar apreensão inicialmente, contudo, este guia visa elucidar os fundamentos necessários. Através deste tutorial, construiremos uma aplicação prática que emprega o roteamento.

O que é Roteamento React (Roteamento do Lado do Cliente)

O roteamento em React é uma metodologia de roteamento do lado do cliente, aplicada em aplicações React. O roteamento do lado do cliente surge como alternativa ao roteamento do lado do servidor. No modelo do lado do servidor, cada vez que o utilizador navega para uma nova página, o navegador envia uma requisição GET ao servidor. Este processo pode consumir alguns segundos até que uma resposta seja recebida.

Numa aplicação web onde a transição entre páginas é constante, este tempo de espera prejudica a experiência do utilizador. O roteamento do lado do cliente surge como uma solução. Ao invés de fornecer HTML ao navegador, a aplicação emprega JavaScript para gerar o HTML para as diversas páginas.

Apenas um arquivo `index.html` é necessário como ponto de partida para a aplicação. Este ponto de entrada carrega o código JavaScript. O pacote JavaScript irá então renderizar as páginas, manipular o DOM, gerir o roteamento e implementar a funcionalidade da aplicação.

Dado que o servidor apenas renderiza a página `index.html`, a aplicação é referida como uma aplicação de página única.

Benefícios do Roteamento do Lado do Cliente

  • Proporciona uma experiência de utilizador aprimorada, dado que a navegação torna-se mais fluida e a aplicação mais responsiva. Com o roteamento do lado do servidor, cada navegação implica uma solicitação de rede, com latência associada.
  • Permite a criação de aplicações offline, uma vez que todo o código necessário para a execução da aplicação pode ser armazenado localmente. Isso possibilita a criação de aplicações mais acessíveis, oferecendo funcionalidades mesmo sem conexão.
  • A aplicação utiliza menos dados, pois as solicitações de rede são substancialmente reduzidas, enviando tudo uma vez e armazenando alguns arquivos localmente.
  • Reduz a carga sobre o servidor, dado que este necessita renderizar a aplicação apenas uma vez. Isso contrasta com a renderização do lado do servidor, onde o servidor renderiza continuamente a aplicação.

A seguir, vamos explorar como implementar o roteamento em React.

Como Implementar o Roteamento em React

Neste tutorial, vamos construir uma aplicação simples para tomada de notas. Esta será composta por várias páginas. Vamos implementar o roteamento do lado do cliente usando a biblioteca React Router DOM, que possibilita a navegação entre as diferentes páginas. Não vamos focar na construção completa da aplicação, mas sim no roteamento.

Pré-requisitos

Para acompanhar este guia, é necessário possuir conhecimentos em HTML, JavaScript e React. Além disso, o Node.js e o NPM devem estar instalados. Estes podem ser obtidos através do download do Nodejs a partir do site oficial. Alternativamente, pode seguir o guia no vídeo do YouTube incorporado.

O que Vamos Construir

A aplicação consistirá em diversas páginas. Utilizando o roteamento em React, será possível navegar entre estas páginas. Os layouts das páginas são apresentados a seguir.

A página inicial é renderizada na rota ‘/’.

A página ‘Sobre’ é apresentada na rota ‘/about’.

A página de notas é acessível na rota ‘/notes’.

A página para criar novas notas encontra-se na rota ‘/notes/new’.

É possível visualizar cada nota na íntegra na página de notas individual. Esta página é renderizada na rota ‘/routes/’, onde é um número inteiro que representa o identificador da nota a ser visualizada.

Primeiros Passos

Para começar, crie um novo projeto React. Para este guia, utilizaremos o Vite, sendo o comando para a criação de um novo projeto o seguinte:

npm create vite@latest scribbble --template react

Neste comando, ‘scribbble’ é o nome atribuído ao projeto, e o template escolhido é o React. A seguir, vamos abrir o VS Code, utilizando os comandos abaixo:

cd scribbble
code .

Após o VS Code estar aberto, retorne à janela do terminal e instale a biblioteca react-router-dom. Este pacote simplifica a implementação do roteamento em aplicações React.

npm install react-router-dom

Vamos criar um arquivo onde as notas serão armazenadas. Crie um arquivo `src/notes.js` e adicione o seguinte código:

const notes = [
  {
    id: 1,
    title: "Nota 1",
    body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
  },
  {
    id: 2,
    title: "Nota 2",
    body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
  },
  {
    id: 3,
    title: "Nota 3",
    body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
  },
];

export default notes;

Em seguida, exclua o arquivo `src/App.css`. Não o utilizaremos neste projeto. Além disso, certifique-se de remover a importação do arquivo `App.css` do arquivo `App.jsx`.

Após isso, substitua todo o conteúdo do arquivo `index.css` pelo seguinte:

:root{font-family:Inter,system-ui,Avenir,Helvetica,Arial,sans-serif;font-weight:400;color:#404040}*{margin:0;padding:0}.nav-container{display:flex;justify-content:space-between;padding:15px 30px}.home-buttons,.nav{display:flex;gap:10px}a{text-decoration:none;color:inherit;font-weight:600}h1{font-size:63px;margin:20px 0}input,textarea{border:1px solid #f1f1f1;background-color:#fafafa;outline:0;padding:10px;width:100%}textarea{resize:none;font-family:inherit}.container{padding:15px}.primary{background-color:#8a2be2;color:#fff}.secondary{background-color:#eee}.button{padding:15px 30px;font-size:16px;border:none;font-weight:700;border-radius:7px;cursor:pointer}.home-container{height:300px;display:flex;flex-direction:column;align-items:center;justify-content:center}.new-note-container{padding:20px}.new-note-form{display:flex;flex-direction:column;align-items:center;width:500px;gap:20px;margin:auto;border-radius:7px;padding:20px 30px}.notes-list{display:grid;grid-template-columns:1fr 1fr 1fr;gap:30px;padding:0 60px}.note{border:1px solid #d3d3d3;padding:15px;border-radius:7px}.note h2{font-size:1rem;margin-bottom:10px}.note p{color:#585858;font-size:.9rem;cursor:pointer}.note-container{display:flex;align-items:center;justify-content:center;padding:50px}.note-content{width:500px}

Em seguida, crie os seguintes arquivos para as páginas que vamos construir:

  • src/pages/Home.jsx
  • src/pages/Sobre.jsx
  • src/pages/Note.jsx
  • src/pages/NewNote.jsx
  • src/pages/Notes.jsx

Posteriormente, crie o arquivo para o componente Barra de Navegação. Este arquivo deverá estar localizado em `src/components/NavBar.jsx`

Configurando o Roteamento React

Com a nossa aplicação configurada, vamos configurar o roteamento na aplicação.

Abra o arquivo `App.jsx` e exclua todo o conteúdo existente. Em seguida, adicione as seguintes importações ao topo do arquivo:

import { BrowserRouter, Routes, Route } from "react-router-dom";
import { NavBar } from "./components/NavBar";
import { Home } from "./pages/Home";
import { About } from "./pages/About";
import { Notes } from "./pages/Notes";
import { Note } from "./pages/Note";
import { NewNote } from "./pages/NewNote";

Estamos a importar os componentes `BrowserRouter`, `Routes` e `Route` da biblioteca react-router-dom. Estes serão utilizados para configurar o roteador. Adicionalmente, estamos a importar o componente `NavBar` do nosso diretório de componentes e diversas páginas dos nossos arquivos de páginas. Ainda não implementamos as páginas, mas faremos isso em breve.

A seguir, vamos configurar o nosso componente App:

export default App () {

}

Em seguida, adicionamos a seguinte marcação na nossa declaração `return`:

return (
    <BrowserRouter>
      
    </BrowserRouter>
)

Isto renderiza o componente `BrowserRouter`, um componente React fornecido pela biblioteca react-router-dom. Este componente configura um roteador que opera dentro do navegador. A nossa aplicação será encapsulada por estas tags.

A seguir, adicionaremos a barra de navegação e criaremos um componente `Routes`.

return (
    <BrowserRouter>
      <NavBar />
      <div className="container">
        <Routes>
          
        </Routes>
      </div>
    </BrowserRouter>
  );

Dentro do elemento `BrowserRouter`, adicionamos um componente `NavBar`. Definiremos este elemento mais tarde, mas ele cria os links no topo de cada página. Em vez de o escrevermos separadamente para cada página, criaremos um componente `NavBar`.

Em seguida, criamos um elemento `container`. Este elemento não é necessário para o roteamento. Apenas adicionamos para aplicar estilo.

Dentro do `container`, adicionamos o componente `Routes`. É aqui que as diferentes páginas serão renderizadas dependendo da rota em que o navegador se encontra. Tudo dentro do componente `Routes` será renderizado novamente sempre que a rota for alterada.

Finalmente, adicionamos as rotas para as diferentes páginas.

  return (
    <BrowserRouter>
      <NavBar />
      <div className="container">
        <Routes>
          <Route path="/" Component={Home} />
          <Route path="about" Component={About} />
          <Route path="notes" Component={Notes}>
            <Route path="new" Component={NewNote} />
            <Route path=":id" Component={Note} />
          </Route>
        </Routes>
      </div>
    </BrowserRouter>
  );

O componente `Home` será renderizado quando o caminho for ‘/’, e o componente `About` será renderizado na rota ‘/about’. O componente `Notes` será renderizado na rota ‘/notes’. Também temos a rota ‘/notes/new’ e ‘/notes/:id’ definidas como rotas aninhadas.

Rotas Aninhadas Explicadas

Uma rota pode conter rotas internas. Estas são denominadas rotas aninhadas. O caminho para estas rotas aninhadas será concatenado com a rota pai para formar o caminho completo. Por exemplo, as rotas ‘notes’ e ‘new’ serão combinadas em ‘/notes/new’.

Em relação à forma como os componentes são renderizados quando o utilizador navega para a rota pai, apenas o componente pai será renderizado. No entanto, tanto o componente pai como o aninhado serão renderizados em conjunto quando a navegação ocorrer para a rota aninhada.

Para renderizar ambos os componentes em conjunto, o componente `Notes` deve renderizar um componente `Outlet` que especifica o local onde o componente `Note` será incorporado. Veremos isto mais tarde, quando começarmos a construir as páginas.

Rotas Dinâmicas

Até agora, especificamos a rota literal que pretendemos corresponder. Por exemplo, as rotas ‘/’ e ‘about’. No entanto, a biblioteca react-router-dom permite especificar rotas dinâmicas. Uma rota dinâmica contém uma parte que pode ser equiparada a um parâmetro de consulta. Quando ocorre a correspondência, o parâmetro de consulta é transmitido para a página.

Por exemplo, dentro da rota pai ‘posts’, temos uma rota aninhada que contém uma parte dinâmica especificada por `:id`. Esta rota aceita qualquer texto na posição de `:id`, e este texto fica disponível para o componente `Note` como identificador (`id`).

Construindo a Barra de Navegação

Utilizamos componentes `Link` em vez de tags âncora normais para navegar usando a biblioteca react-router-dom. Assim, a nossa barra de navegação deverá ter o seguinte aspeto:

import { Link } from "react-router-dom";

export function NavBar() {
  return (
    <div className="nav-container">
      <Link to="/">Scribbble</Link>
      <nav className="nav">
        <Link to="/about">Sobre</Link>
        <Link to="/notes">Notas</Link>
        <Link to="/notes/new">Nova Nota</Link>
      </nav>
    </div>
  );
}

Adicione este código a `src/pages/NavBar.jsx`.

Construindo as Páginas

A seguir, vamos construir as páginas. Para a página inicial, adicione o seguinte código a `src/pages/Home.jsx`.

import { useNavigate } from "react-router-dom";

export function Home() {
  const navigate = useNavigate();

  return (
    <div className="home-container">
      <h1>Notas para Profissionais</h1>
      <div className="home-buttons">
        <button
          onClick={() => {
            navigate("/notes/new");
          }}
          className="button primary"
        >
          Começar a Escrever
        </button>
        <button
          onClick={() => {
            navigate("/notes");
          }}
          className="button secondary"
        >
          Visualizar Notas
        </button>
      </div>
    </div>
  );
}

Na página inicial, queremos usar botões para navegar. Como resultado, utilizamos o hook `useNavigate` para navegar programaticamente. Importamos o hook e o invocamos dentro do componente `Home`. O valor de retorno após a invocação do hook é uma função que pode ser usada para navegar.

A seguir, definiremos a página ‘Sobre’. Adicione o código seguinte ao seu arquivo `src/pages/About.jsx`.

export function About() {
  return (
    <div>
      <h1>Sobre</h1>
      <p>Simple Notes é a melhor aplicação de tomada de notas para profissionais</p>
    </div>
  );
}

Depois disso, definiremos a página de Notas.

Neste componente, devemos também incluir um componente `Outlet` que será usado para renderizar quaisquer rotas aninhadas. Por esta razão, a nossa página `src/pages/Notes.jsx` terá o seguinte aspeto.

import { Outlet, useNavigate } from "react-router-dom";
import notes from "../notes";

export function Notes() {
  const navigate = useNavigate();
  return (
    <div>
      <Outlet />
      <div className="notes-list">
        {notes.map((note) => {
          return (
            <div
              className="note"
              key={note.id}
              onClick={() => {
                navigate("/notes/" + note.id);
              }}
            >
              <h2>{note.title}</h2>
              <p>{note.body.slice(0, 100)}</p>
            </div>
          );
        })}
      </div>
    </div>
  );
}

A seguir, vamos definir a página Nota.

Isto será renderizado para uma nota individual. Para decidir qual nota deve ser renderizada, o componente `Notes` irá aceder ao identificador especificado na parte dinâmica da rota. Para fazer isso, usamos o hook `userParams`. Portanto, este deve ser o código dentro do seu arquivo `src/pages/Note.jsx`:

import { useParams } from "react-router-dom";
import notes from "../notes";

export function Note() {
  const params = useParams();
  const note = notes.find((note) => note.id == params.id);
  return (
    <div className="note-container">
      <div className="note-content">
        <h2>{note.title}</h2>
        <p>{note.body}</p>
      </div>
    </div>
  );
}

Por último, vamos criar o componente `NewNote` dentro de `src/pages/NewNote.jsx` utilizando o seguinte código:

export function NewNote() {
  return (
    <div class="new-note-container">
      <form class="new-note-form">
        <h2>Nova Nota</h2>
        <input type="text" name="title" placeholder="Título da Nota" />
        <textarea rows="10" placeholder="Texto da Nota" />
        <button class="button primary">Guardar Nota</button>
      </form>
    </div>
  );
}

Neste ponto, escrevemos todo o código da aplicação. Pode executar a aplicação utilizando o comando `npm run dev`. Navegue para páginas diferentes e veja a velocidade do roteamento do lado do cliente.

Desvantagens do Roteamento do Lado do Cliente

Apesar dos seus múltiplos benefícios, o roteamento do lado do cliente apresenta diversas desvantagens. Estas são explicadas abaixo:

  • O carregamento inicial da página pode ser lento, uma vez que toda a aplicação precisa de ser carregada. O pacote JavaScript pode ser bastante grande, levando a tempos de carregamento demorados.
  • Dado que a marcação é gerada por JavaScript, a página não será otimizada para SEO.
  • Uma vez que tudo depende do JavaScript, os navegadores que não suportam JavaScript ou que têm JavaScript desativado não conseguirão executar a aplicação.

Conclusão

Neste artigo, abordamos o tema do roteamento em React, construindo um pequeno projeto. Embora não tenhamos coberto tudo, este guia aborda conceitos que serão utilizados na maioria dos projetos em que vier a trabalhar. Para mais informações sobre a biblioteca react-router-dom, consulte os documentos oficiais.

A seguir, leia este artigo sobre bibliotecas de formulários em React.