Henrique Schroeder
8/9/2022 Henrique Schroeder

React Router Dom

blog-feature-image

Fala meus consagrados, tudo bem com vocês?

Hoje vamos abordar a manipulação de rotas dentro de um projeto React utilizando a biblioteca react-router-dom.

Obs: Para ter melhor entendimento do conteúdo, você precisa ter um conhecimento básico de JavaScript e React.


Em um site da web, onde temos muitas telas e precisamos acessá-las de maneira dinâmica e rápida, utilizar rotas para a navegação do usuário é a melhor solução. Existem muitas ferramentas que resolvem esse tipo de problema, mas para as pessoas que desenvolvem em React, o React Router Dom é o mais aconselhável.


💻 React router dom

O React Router Dom é uma biblioteca para React criada para facilitar a manipulação de rotas. Com ela, podemos declarar caminhos do nosso site para renderizar componentes e até mesmo resolver parâmentros na URL.


⚙️ Instalação

A maioria dos projetos React modernos gerenciam suas dependências usando um gerenciador de pacotes como npm ou Yarn. Para adicionar o React Router a um projeto existente, a primeira coisa que você deve fazer é instalar as dependências necessárias com a ferramenta de sua escolha.

npm install react-router-dom
yarn add react-router-dom
pnpm add react-router-dom

🧾 Configurando Rotas

import { render } from "react-dom";
import {
  BrowserRouter,
  Routes,
  Route,
} from "react-router-dom";
// importe seus componentes aqui

render(
  <BrowserRouter>
    <Routes>
      <Route path="/" element={<App />}>
        <Route index element={<Home />} />
        <Route path="books" element={<Books />}>
          <Route path=":bookId" element={<Book />} />
          <Route path="new" element={<NewBookForm />} />
        </Route>
      </Route>
    </Routes>
  </BrowserRouter>,
  document.getElementById("root")
);

Nas versões anteriores do React Router, você precisava ordenar suas rotas de uma certa maneira para obter a correta para renderizar quando várias rotas correspondiam a uma URL ambígua. O V6 é muito mais inteligente e escolherá a correspondência mais específica para que você não precise mais se preocupar com isso. Por exemplo, o URL /books/newcorresponde a ambas as rotas:

<Route path="books/:bookId" element={<Book />} />

<Route path="books/new" element={<NewBookForm />} />

Mas books/new é uma correspondência mais específica do que /books/:bookId, então <NewBookForm />será renderizada.


⚓ Navegação

Use Link para permitir que o usuário altere a URL ou useNavigate faça você mesmo (como após o envio do formulário):

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

function Home() {
  return (
    <div>
      <h1>Home</h1>
      <nav>
        <Link to="/">Home</Link> |{" "}
        <Link to="about">About</Link>
      </nav>
    </div>
  );
}

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

function Books() {
  const navigate = useNavigate();
  return (
    <div>
      <NewBookForm
        onSubmit={async (event) => {
          let newBook = await createBook(
            event.target
          );
          navigate(`/books/${newBook.id}`);
        }}
      />
    </div>
  );
}

📚 Lendo parâmetros de URL

Use :style a sintaxe em seu caminho de rota e useParams() para lê-los:

import { Routes, Route, useParams } from "react-router-dom";

function App() {
  return (
    <Routes>
      <Route
        path="books/:booksId"
        element={<Book />}
      />
    </Routes>
  );
}

function Book() {
  let params = useParams();
  return <h1>Livro {params.booksId}</h1>;
}

Observe que o segmento do caminho :bookId e a chave do parâmetro params.bookId coincidem.

Um caso de uso muito comum é buscar dados quando o componente renderiza:

function Book() {
  const { bookId } = useParams();
  const book = useFakeFetch(`/api/books/${bookId}`);
  return book ? (
    <div>
      <h1>{book.customerName}</h1>
    </div>
  ) : (
    <Loading />
  );
}

🚦 Rotas aninhadas

Este é um dos recursos mais poderosos do React Router, fazendo com que você não precise mexer com códigos de layout complicados. A grande maioria de seus layouts são acoplados a segmentos da URL e o React Router abraça isso totalmente.

As rotas podem ser aninhadas umas dentro das outras, e seus caminhos também serão aninhados (filho herdando o pai).

function App() {
  return (
    <Routes>
      <Route path="books" element={<Books />}>
        <Route path=":bookId" element={<Book />} />
        <Route path="sent" element={<SentBooks />} />
      </Route>
    </Routes>
  );
}

Esta configuração de rota definiu três caminhos de rota:

  • "/books"
  • "/books/sent"
  • "/books/:bookId"

Quando a URL for "/books/sent" a árvore de componentes será:

<App>
  <Books>
    <SentBooks />
  </Books>
</App>

Quando a URL for "/books/123", a árvore de componentes:

<App>
  <Books>
    <Book />
  </Books>
</App>

Observe o componente interno que mudou com a URL ( <SentBooks><Book> ). A rota pai ( <Books> ) é responsável por garantir que a rota filha correspondente seja renderizada com <Outlet>. Aqui está o exemplo completo:

import { Routes, Route, Outlet } from "react-router-dom";

function App() {
  return (
    <Routes>
      <Route path="books" element={<Books />}>
        <Route path=":bookId" element={<Book />} />
        <Route path="sent" element={<SentBooks />} />
      </Route>
    </Routes>
  );
}

function Books() {
  return (
    <div>
      <h1>Livros</h1>
      <Outlet />
    </div>
  );
}

function Book() {
  const { bookId } = useParams();
  return <h1>Livro {bookId}</h1>;
}

function SentBooks() {
  return <h1>Livros enviados</h1>;
}

Os segmentos de URL aninhados são mapeados para árvores de componentes aninhados. Isso é perfeito para criar UI que tenha navegação persistente em layouts com uma seção interna que muda com a URL. Se você olhar na web, notará que muitos sites (e especialmente aplicativos da web) têm vários níveis de aninhamento de layout.

Aqui está outro exemplo de um layout raiz com navegação que persiste enquanto a página interna é trocada pela URL:

import {
  Link,
  Route,
	Routes,
  Outlet,
} from "react-router-dom";

function App() {
  return (
    <Routes>
      <Route path="/" element={<Layout />}>
        <Route path="books" element={<Books />} />
        <Route path="dashboard" element={<Dashboard />} />
      </Route>
    </Routes>
  );
}

function Layout() {
  return (
    <div>
      <h1>Bem-vindo ao aplicativo!</h1>
      <nav>
        <Link to="books">Livros</Link> |{" "}
        <Link to="dashboard">Dashboard</Link>
      </nav>
      <div className="content">
        <Outlet />
      </div>
    </div>
  );
}

function Books() {
  return <h1>Livros</h1>;
}

function Dashboard() {
  return <h1>Dashboard</h1>;
}

🚦 Rotas de índice

As rotas de índice podem ser consideradas como “rotas filhas padrão”. Quando uma rota pai tem vários filhos, mas a URL está apenas no caminho do pai, você provavelmente deseja renderizar algo na saída.

Considere este exemplo:

function App() {
  return (
    <Routes>
      <Route path="/" element={<Layout />}>
        <Route path="books" element={<Books />} />
        <Route path="activity" element={<Activity />} />
      </Route>
    </Routes>
  );
}

function Layout() {
  return (
    <div>
      <GlobalNav />
      <main>
        <Outlet />
      </main>
    </div>
  );
}

Esta página parece ótima em “/books” e “/activity”, mas em “/” é apenas uma página em branco <main> porque não há nenhuma rota filha para renderizar lá. Para isso, podemos adicionar uma rota de índice:

function App() {
  return (
    <Routes>
      <Route path="/" element={<Layout />}>
        <Route index element={<Activity />} />
        <Route path="books" element={<Books />} />
        <Route path="activity" element={<Activity />} />
      </Route>
    </Routes>
  );
}

Agora em “/” o <Activity> elemento irá renderizar dentro da saída.

Você pode ter uma rota de índice em qualquer nível da hierarquia de rotas que será renderizada quando o pai corresponder, mas nenhum de seus outros filhos o fizer.

function App() {
  return (
    <Routes>
      <Route index element={<Home />} />
      <Route path="dashboard" element={<Dashboard />}>
        <Route index element={<DashboardHome />} />
        <Route
          path="books"
          element={<DashboardBooks />}
        />
      </Route>
    </Routes>
  );
}

Os valores relativos <Link to> (que não começam com /) são relativos ao caminho da rota que os renderizou. Os dois links abaixo serão vinculados a /dashboard/books/dashboard/post porque são renderizados dentro de <Dashboard>. Isso é muito bom quando você altera a URL de um pai ou reorganiza seus componentes porque todos os seus links são atualizados automaticamente.

import {
  Link,
  Route,
  Routes,
  Outlet,
} from "react-router-dom";

function Home() {
  return <h1>Home</h1>;
}

function Dashboard() {
  return (
    <div>
      <h1>Dashboard</h1>
      <nav>
        <Link to="books">Livros</Link>{" "}
        <Link to="posts">Postagens</Link>
      </nav>
      <hr />
      <Outlet />
    </div>
  );
}

function Books() {
  return <h1>Livros</h1>;
}

function Posts() {
  return <h1>Postagens</h1>;
}

function App() {
  return (
    <Routes>
      <Route path="/" element={<Home />} />
      <Route path="dashboard" element={<Dashboard />}>
        <Route path="books" element={<Books />} />
        <Route path="posts" element={<Posts />} />
      </Route>
    </Routes>
  );
}

🕵🏻 Rotas “Não Encontradas”

Quando nenhuma outra rota corresponde ao URL, você pode renderizar uma rota “não encontrada” usando path="*". Essa rota corresponderá a qualquer URL, mas terá a precedência mais fraca, de modo que o roteador a escolherá apenas se nenhuma outra rota corresponder.

function App() {
  return (
    <Routes>
      <Route path="/" element={<Home />} />
      <Route path="dashboard" element={<Dashboard />} />
      <Route path="*" element={<NotFound />} />
    </Routes>
  );
}

🔀 Vários conjuntos de rotas

Embora você deva ter apenas um single <Router> em um aplicativo, você pode ter quantos <Routes> precisar, onde quer que precise deles. Cada <Routes> elemento opera independentemente dos outros e escolhe uma rota filha para renderizar.

function App() {
  return (
    <div>
      <Sidebar>
        <Routes>
          <Route path="/" element={<MainNav />} />
          <Route
            path="dashboard"
            element={<DashboardNav />}
          />
        </Routes>
      </Sidebar>

      <MainContent>
        <Routes>
          <Route path="/" element={<Home />}>
            <Route path="about" element={<About />} />
            <Route path="support" element={<Support />} />
          </Route>
          <Route path="dashboard" element={<Dashboard />}>
            <Route path="books" element={<Books />} />
            <Route path="posts" element={<Posts />} />
          </Route>
          <Route path="*" element={<NotFound />} />
        </Routes>
      </MainContent>
    </div>
  );
}

😶‍🌫️ Descendente<Routes>

Você pode renderizar um <Routes> elemento em qualquer lugar que precisar, inclusive no fundo da árvore de componentes de outro arquivo <Routes>. Eles funcionarão da mesma forma que qualquer outro <Routes>, exceto que serão construídos automaticamente no caminho da rota que os renderizou. Se você fizer isso, certifique-se de colocar um * no final do caminho da rota pai . Caso contrário, a rota pai não corresponderá à URL quando for maior que o caminho da rota pai e seu descendente <Routes> nunca aparecerá.

function App() {
  return (
    <Routes>
      <Route path="/" element={<Home />} />
      <Route path="dashboard/*" element={<Dashboard />} />
    </Routes>
  );
}

function Dashboard() {
  return (
    <div>
      <p>Olha, mais rotas!</p>
      <Routes>
        <Route path="/" element={<DashboardGraphs />} />
        <Route path="Books" element={<BookList />} />
      </Routes>
    </div>
  );
}

E é só isso! Não foi abordado todas as APIs aqui, mas essas são definitivamente as mais comuns que você usará.


🔗 Referências


comments powered by Disqus

NOS ACOMPANHE NAS REDES SOCIAIS