Como criar links e rotas com React Router Dom v6

Introdução

Eu tenho mais familiaridade com o backend, mas por gostar muito de javascript, o ReactJS sempre está nas minhas trilhas de aprendizado.

Buscando mais informações sobre as rotas, algumas questões que não ficavam claras para mim era o carregamento de telas e navegação entre elas com toda aquela parafernalha que o front precisa carregar: css, js, libs, componentes, etc, sendo que nem sempre existe a necessidade de ir no backend para resolver algo.

Este post pode ser básico se você já possui um conhecimento sólido do ReactJS, mas pode auxiliar alguém que esteja iniciando.

Nesta publicação você vai ver

Objetivo

Vamos construir uma aplicação com carregamento de duas telas: clientes e produtos e permitir a navegação entre essas elas sem o carregamento total da página. A tela de clientes possuirá uma listagem permitindo a visualização dos detalhes de cada cliente com uma navegação interna.

O repositório completo fica neste link: https://github.com/tiagosabadini/navegacao-react-router-dom6.

Criando a aplicação

Antes de tudo, vamos criar nossa aplicação. E, dentro da pasta do novo projeto, vamos instalar a versão 6 do react-router-dom.

npx create-react-app navegacao-react
cd navegacao-react
npm install react-router-dom@6

Acesse o projeto com seu editor de códigos favorito e deixe dentro da pasta src apenas os arquivos App.js e index.js com o código abaixo. Rode o comando npm start para ver se está tudo certo no navegador.

//App.js
export default function App() {
  return (
    <div>
      <h1>Gestão de Lojinha</h1>
    </div>
  );
}

//index.js
import { render } from "react-dom";
import App from "./App";

const rootElement = document.getElementById("root");
render(<App />, rootElement);

Sem surpresas até aqui, apenas um texto impresso no navegador.

Conectando a URL

Agora precisamos conectar nossa aplicação com a URL do navegador, importando o BrowserRouter e envolvendo nosso App com ele.

import { render } from "react-dom";
import { BrowserRouter } from "react-router-dom";
import App from "./App";

const rootElement = document.getElementById("root");
render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  rootElement
);

Agora para vermos algumas coisas funcionando por aqui, vamos adicionar alguns links e rotas na nossa aplicação. Importe o componente Link , adicione no seu App.js e crie links para as páginas de clientes e produtos.

//App.js
import { Link } from "react-router-dom";

export default function App() {
  return (
    <div>
      <h1>Gestão de Lojinha</h1>

      <nav
        style={{
          borderBottom: "solid 2px green",
          paddingBottom: "1rem",
        }}
      >
        
        <Link to="/clientes">Clientes</Link> |{" "}
        <Link to="/produtos">Produtos</Link>
      </nav>
    </div>
  );
}

//index.js
import { render } from "react-dom";
import { BrowserRouter } from "react-router-dom";
import App from "./App";

const rootElement = document.getElementById("root");
render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  rootElement
);

Perceba que a navegação funciona, o link no navegador é alterado conforme o clique do usuário e a tela não é recarregada. Agora precisamos criar as rotas e apontar para os componentes corretos.

As rotas serão criadas dentro do index.js e informará ao React quais componentes serão carregados quando uma determinada rota for acionada.

Crie uma pasta chamada routes e adicione os arquivos clientes.js e produtos.js .

//./routes/clientes.js
export default function Clientes(){
  return (
    <h1>Clientes</h1>
  );
}

//./routes/produtos.js
export default function Produtos(){
  return (
    <h1>Produtos</h1>
  );
}

Já no arquivo index.js vamos importar Routes, Route e os componentes Clientes e Produtos que acabamos de criar.

import { render } from "react-dom";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import App from "./App";
import Clientes from "./routes/clientes";
import Produtos from "./routes/produtos";

const rootElement = document.getElementById("root");
render(
  <BrowserRouter>
    <Routes>
      <Route path="/" element={<App />} />
      <Route path="/clientes" element={<Clientes />} />
      <Route path="/produtos" element={<Produtos />} />
    </Routes>
  </BrowserRouter>,
  rootElement
);

A navegação ficou mais interessante agora, mas veja que ao acessar a tela de clientes ou produtos, o layout padrão some. Isso acontece porque o layout com o menu está apenas no componente App e não é compartilhado entre as demais telas da aplicação.

Você pode pensar em repetir o menu em todos os componentes ou carregar os demais componentes dentro do componente principal App para tentar resolver esse problema, mas podemos resolver de uma forma mais interessante.

Rotas aninhadas

Para compartilhar o layout do App vamos colocar as rotas clientes e produtos dentro de index.js como filhas da Rota com path “/”.

Dentro de App importe o componente Outlet e adicione-o antes do fechamento da última <div> .

import { render } from "react-dom";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import App from "./App";
import Clientes from "./routes/clientes";
import Produtos from "./routes/produtos";

const rootElement = document.getElementById("root");
render(
  <BrowserRouter>
    <Routes>
      <Route path="/" element={<App />}>
        <Route path="/clientes" element={<Clientes />} />
        <Route path="/produtos" element={<Produtos />} />
      </Route>
    </Routes>
  </BrowserRouter>,
  rootElement
);
import { Link, Outlet } from "react-router-dom";

export default function App() {
  return (
    <div>
      <h1>Gestão de Lojinha</h1>
      <nav
        style={{
          borderBottom: "solid 2px green",
          paddingBottom: "1rem",
        }}
      >
        <Link to="/clientes">Clientes</Link> |{" "}
        <Link to="/produtos">Produtos</Link>
      </nav>
      <Outlet />
    </div>
  );
}

As rotas aninhadas possuem paths relativos. Quando criamos uma rota pai com path “admin”, por exemplo, as rotas filho serão sempre “admin/path-da-rota”. O prefixo “admin” está implícito, não é necessário incluir no path das rotas filho.

Listando clientes

Normalmente a gente busca dados de algum servidor, mas vamos colocar alguns dados fake aqui para focarmos na navegação e rotas.

Adicione um arquivo data.js na raiz da pasta src e importe o arquivo dentro do componente routes/clientes.js .

let clientes = [
  {
    "id": 1,
    "nome": "joão da silva",
    "idade": 22,
    "local_nascimento": "rio de janeiro",
  },
  {
    "id": 2,
    "nome": "maria helena",
    "idade": 32,
    "local_nascimento": "são paulo",
  },
  {
    "id": 3,
    "nome": "jonas almeida",
    "idade": 44,
    "local_nascimento": "minas gerais",
  },
  {
    "id": 4,
    "nome": "juliana maria talgaz",
    "idade": 26,
    "local_nascimento": "minas gerais",
  },
  {
    "id": 5,
    "nome": "tereza maria",
    "idade": 54,
    "local_nascimento": "minas gerais",
  },
  {
    "id": 6,
    "nome": "jober joelson silva",
    "idade": 28,
    "local_nascimento": "são paulo",
  },
  {
    "id": 7,
    "nome": "mariana silva",
    "idade": 20,
    "local_nascimento": "rio de janeiro",
  },
  {
    "id": 8,
    "nome": "roberto manejo",
    "idade": 21,
    "local_nascimento": "rio de janeiro",
  },
];

export function getClientes() {
  return clientes;
}

O componente clientes.js receberá agora um loop com map() para imprimir os links e permitir a exibição dos detalhes de cada cliente quando forem clicados.

import {Link} from 'react-router-dom';
import {getClientes} from '../data';

export default function Clientes(){
  let clientes = getClientes();

  return (
    <div style={{display: "flex"}}>
      <nav
        style={{
          borderRight: "solid 2px green",
          padding: "1rem",
          marginRight: "2rem",
        }}
      >

      {
        clientes.map((cliente) => {
          return <Link
            style={{
              display: "block",
              margin: "1rem 0",
            }}
            to={`/clientes/${cliente.id}`} key={cliente.id}>
            {cliente.nome}
          </Link>
        })
      }

      </nav>
    </div>
    
  );
}

Agora quando clicamos no link de cada cliente, a tela fica em branco. Para resolver isso vamos repetir o processo que fizemos lá no início. Criando um aninhamento para a rota de clientes e importando Outlet dentro de Clientes para compartilhar o layout do componente principal.

Para exibirmos os detalhes de cada cliente, vamos criar um novo componente dentro de routes chamado cliente.js . Ele vai receber os parâmetros da URL e buscar os detalhes do cliente selecionado.

import {useParams} from 'react-router-dom';
import {getCliente} from '../data';

export default function Cliente(){
  const params = useParams();
  const cliente = getCliente(parseInt(params.clienteId, 10));

  return (
    <main style={{ padding: "1rem" }}>
      <h2>Nome: {cliente.nome}</h2>
      <p>
        {cliente.nome}: #{cliente.id}
      </p>
      <p>Idade: {cliente.idade}</p>
      <p>Local de Nascimento: {cliente.local_nascimento}</p>      
    </main>
  );
}

Apenas criar o componente não vai fazer a aplicação funcionar, precisamos adicionar a rota para que o React saiba o que fazer quando esse link for acionado.

import { render } from "react-dom";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import App from "./App";
import Clientes from "./routes/clientes";
import Cliente from "./routes/cliente";
import Produtos from "./routes/produtos";

const rootElement = document.getElementById("root");
render(
  <BrowserRouter>
    <Routes>
      <Route path="/" element={<App />}>
        <Route path="clientes" element={<Clientes />}>
          <Route path=":clienteId" element={<Cliente />} />
        </Route>
        <Route path="produtos" element={<Produtos />} />
      </Route>
    </Routes>
  </BrowserRouter>,
  rootElement
);
Resultado final

Conclusão

Espero que esta postagem tenha contribuído para você. Caso queira acessar o repositório completo, veja este link: https://github.com/tiagosabadini/navegacao-react-router-dom6.

Conhecimento é algo que ninguém pode tirar de você e quando é compartilhado não se perde, multiplica.