Entendendo o roteamento com segmentos dinâmicos no Next.js

Entendendo o roteamento com segmentos dinâmicos no Next.js
Vinicios Neves
Vinicios Neves

Compartilhe

O roteamento de páginas numa aplicação web desempenha um papel muito importante, permitindo que os usuários naveguem de maneira fluida entre várias páginas ou seções. Isso torna a experiência do usuário mais intuitiva e eficiente.

Neste artigo, vamos explorar as poderosas funcionalidades de roteamento do Next.js e focar especificamente no novo App Router, que traz ainda mais flexibilidade e simplicidade para a criação de rotas na sua aplicação.

Como começar

Para começar, crie e execute um novo projeto Next.js 14 usando os seguintes comandos no terminal:


npx create-next-app@latest routing-app
cd routing-app
npm run dev

Abra o projeto no seu editor de código preferido e expanda a pasta src. Para começar do zero, delete a pasta app para criar apenas as rotas que serão utilizadas.

Banner promocional da Alura, com um design futurista em tons de azul, apresentando o texto

Convenções de roteamento

O Next.js emprega um mecanismo de roteamento baseado no sistema de arquivos, onde os caminhos de URL no navegador são determinados por arquivos e pastas na base de código.

Seguir as convenções é importante para o funcionamento do roteamento.

Como criar uma rota

Para criar uma rota para a URL raiz (localhost:3000), siga estas etapas:

1 - Crie uma pasta src/app;

2 - Dentro da pasta app, crie um arquivo page.tsx. Este arquivo representa a rota;

3 - Defina um componente React simples no arquivo page.tsx para representar a página "Home":


export default function Home() {
  return <h1>Nem tudo o que é ouro reluz, nem todos os que vagam estão perdidos.</h1>;
}

Seguindo essas convenções, criamos nossa primeira rota com sucesso. Então, abra seu navegador e navegue para localhost:3000 para ver a mensagem do mago Gandalf.

Adicionando rotas adicionais

Vamos agora criar mais duas rotas: uma para a página About e outra para a página Profile.

1 - Crie uma pasta src/app/about;

2 - Dentro da pasta about, crie um arquivo page.tsx. Este arquivo representa a rota;

3- Defina um componente React no arquivo page.tsx para representar a página "About":


export default function About() {
  return <h1>Mesmo na escuridão mais densa, uma luz pode brilhar e mostrar o caminho.</h1>;
}

Agora precisamos fazer o mesmo para a página de perfil, certo?

1 - Crie uma pasta src/app/profile;

2 - Dentro da pasta profile, crie um arquivo page.tsx. Este arquivo representa a rota;

3 - Defina um componente React no arquivo page.tsx para representar a página "Profile":


export default function Profile() {
  return <h1>Gandalf? Sim... Esse era o meu nome. Gandalf, o Cinzento. Sou Gandalf, o Branco agora.</h1>;
}

Quando você visitar a URL http://localhost:3000, a página inicial será exibida. Mas quando você navegar para http://localhost:3000/about, verá a página "About". Da mesma forma, alterando a URL para /profile será exibida a página "Profile".

Isso é o roteamento baseado em arquivos! Podemos identificar que as rotas estão associadas a um arquivo com base no nome da pasta que o contém dentro da pasta app.

Lidando com rotas não correspondentes

Já parou para pensar o que acontece se você digitar uma URL que não pode ser mapeada para um arquivo dentro da pasta app? Por exemplo, /dashboard, que não existe no nosso projeto.

Bom, o Next.js responderá automaticamente com uma resposta 404 Not Found. Você não precisa lidar com isso se não quiser, porque o Next.js cuida disso para você.

Podemos, no entanto, lidar com erros de forma amigável e apresentar mensagens customizadas para a pessoa que está interagindo com nossa aplicação.

Gif com o Gandalf falando a frase: “I have no memory of this place”, que significa “Não tenho lembranças desse lugar”.

Rotas aninhadas

Além das rotas básicas, o Next.js oferece suporte para rotas aninhadas, permitindo que você estabeleça uma estrutura hierárquica dentro da sua aplicação.

Vamos renderizar uma página quando o usuário navegar para a URL http://localhost:3000/blog. Além disso, precisamos renderizar páginas para http://localhost:3000/blog/first e http://localhost:3000/blog/second.

Para implementar rotas aninhadas, siga estas etapas:

1 - Crie uma pasta src/app/blog;

2 - Dentro da pasta blog, crie um arquivo page.tsx para a página principal do blog:


export default function Blog() {
  return <h1>Há sempre algo de bom para aqueles que procuram.</h1>;
}

3 - Navegue para http://localhost:3000/blog para ver a página que acabamos de criar.

Mas não é só isso, temos ainda que implementar as rotas /blog/first e /blog/second. Seguindo o mesmo padrão:

4 -rie arquivos page.tsx nas pastas src/app/blog/first e src/app/blog/second:


// src/app/blog/first/page.tsx
export default function FirstBlog() {
  return <h1>Grandes feitos não são realizados pela força, mas pela perseverança e pela sabedoria.</h1>;
}

// src/app/blog/second/page.tsx
export default function SecondBlog() {
  return <h1>As inscrições na porta são antigas runas élficas. Dizem: 'As portas de Durin, Senhor de Moria. Fale, amigo, e entre.</h1>;
}

Rotas dinâmicas

Em vez de criar caminhos predefinidos como /blog/first e /blog/second para cada página, podemos usar rotas dinâmicas para tornar o processo mais eficiente.

Para ilustrar, vamos usar um exemplo inspirado em um famoso mago de uma história épica.

Criando rotas dinâmicas

Vamos criar uma lista de personagens e uma página de detalhes para cada um. Siga estes passos:

1 - Crie uma pasta src/app/characters;

2 - Dentro da pasta characters, crie um arquivo page.tsx para exibir uma lista de personagens:


export default function CharacterList() {
  return (
    <>
      <h1>Lista de Personagens</h1>
      <h2>Gandalf</h2>
      <h2>Frodo</h2>
      <h2>Aragorn</h2>
    </>
  );
}

Criando a página de detalhes

Para a página de detalhes de cada personagem, siga estes passos:

1 - Dentro da pasta characters, crie uma nova pasta chamada [characterId]. Os colchetes indicam um segmento de rota dinâmico;

2 - Dentro da pasta [characterId], crie um arquivo page.tsx:


export default function CharacterDetail() {
  return <h1>Detalhes sobre o personagem</h1>;
}

Agora, quando você navega para localhost:3000/characters/gandalf, verá a página de detalhes do personagem.

Da mesma forma, acessando /characters/frodo, /characters/aragorn, ou mesmo /characters/legolas exibirá a mesma página de detalhes. [characterId] é o segmento de rota dinâmico que pode acomodar valores como gandalf, frodo, aragorn e assim por diante.

Exibindo o ID específico do personagem

Para exibir o ID específico do personagem, você pode usar o objeto params disponível em cada página. Modifique o componente da seguinte forma:


export default function CharacterDetail({
  params,
}: {
  params: { characterId: string };
}) {
  return <h1>Detalhes sobre o personagem {params.characterId}</h1>;
}

Agora, quando você navega para http://localhost:3000/characters/gandalf, os detalhes sobre o personagem Gandalf serão exibidos.

Da mesma forma, visitando /characters/legolas exibirá os detalhes sobre Legolas. As rotas dinâmicas são extremamente úteis ao implementar esse padrão de lista-detalhe.

Rotas dinâmicas aninhadas

Agora vamos falar sobre rotas dinâmicas aninhadas, que são essenciais para aplicações complexas que precisam de múltiplos segmentos de rota dinâmicas.

Por exemplo, ao navegar para /characters/gandalf, você espera ver os detalhes de Gandalf. Da mesma forma, ao visitar /characters/gandalf/quotes/1, deve ser exibida a primeira citação de Gandalf. Vamos ver como podemos alcançar isso usando o App Router.

Criando rotas dinâmicas aninhadas

Para criar rotas dinâmicas aninhadas, siga estas etapas:

1 - Crie uma pasta src/app/characters/[characterId]/quotes. Esta estrutura nos leva à rota /characters/[characterId]/quotes. Mas também precisamos de um quoteId dinâmico;

2 - Dentro da pasta quotes, crie uma nova pasta chamada [quoteId]. (lembrando que os colchetes indicam um segmento de rota dinâmico);

3 - Dentro da pasta [quoteId], crie um arquivo page.tsx onde definiremos um componente React para exibir tanto o characterId quanto o quoteId:


export default function QuoteDetail({
  params,
}: {
  params: { characterId: string; quoteId: string };
}) {
  return (
    <h1>
      Citação {params.quoteId} do personagem {params.characterId}
    </h1>
  );
}

Agora, se navegarmos para http://localhost:3000/characters/gandalf/quotes/1 no navegador, o texto esperado será exibido. Da mesma forma, navegando para characterId=gandalf e quoteId=1 refletirá os IDs correspondentes na tela.

Diagrama de estrutura de arquivos exibido em um fundo escuro. A estrutura começa com a pasta "app", que contém a pasta "products". Dentro da pasta "products", há uma subpasta chamada "[productId]", que contém uma subpasta chamada "reviews". Dentro da pasta "reviews", há uma subpasta chamada "[reviewId]", que contém o arquivo "page.tsx". Além disso, dentro da pasta "products" e da pasta "app", há múltiplos arquivos "page.tsx" e há um arquivo "layout.tsx" na raiz da pasta "app". No canto superior direito da imagem, há um ícone de globo, e no canto inferior direito, está o logotipo "alura".

Repara que é possível criar rotas dinâmicas aninhadas utilizando segmentos dinâmicos nos nomes das pastas, o que facilita a construção de aplicações complexas mas bem estruturadas.

Segmentos catch-all

Vamos analisar agora um recurso super útil do Next.js: os segmentos catch-all (e não estou falando sobre Pokémons =]).

Eles permitem um roteamento muito mais flexível, ideal para situações em que você precisa lidar com várias rotas dinâmicas sem criar um arquivo separado para cada uma.

Imagine que estamos criando um site de documentação com vários recursos e conceitos.

Em vez de criar um arquivo para cada rota, podemos usar segmentos catch-all para simplificar o processo.

Para implementar segmentos catch-all, siga estas etapas:

1 - Crie uma pasta src/app/receitas;

2 - Dentro da pasta receitas, crie uma pasta com um nome especial reconhecido pelo Next.js. Use colchetes e três pontos (por exemplo, [...slug]) para incluir um nome de sua escolha;

3 - Dentro da pasta [...slug], crie um arquivo page.tsx com um componente React básico representando a página inicial das receitas:


export default function Receitas() {
  return <h1>Página inicial de receitas</h1>;
}

Usando essa estrutura, o arquivo page.tsx corresponderá a qualquer URL que contenha o segmento /receitas no caminho.

Dessa forma, podemos definir um único arquivo que lida com todos os segmentos de rota na URL.

Acessando diferentes segmentos na URL

Para acessar os diferentes segmentos na URL, utilizamos o objeto params fornecido pelo Next.js.

Por exemplo, navegando para http://localhost:3000/receitas/italiana/pasta, podemos renderizar o seguinte componente:


export default function Receitas({ params }: { params: { slug: string[] } }) {
  if (params.slug.length === 2) {
    return (
      <h1>
        Visualizando receita da cozinha {params.slug[0]}: {params.slug[1]}
      </h1>
    );
  } else if (params.slug.length === 1) {
    return <h1>Visualizando receitas da cozinha {params.slug[0]}</h1>;
  }
  return <h1>Página inicial de receitas</h1>;
}

Pense nos segmentos catch-all como um grande baú que pode conter várias combinações de palavras na URL.

É como se você tivesse um livro de receitas onde cada seção e subseção pode ser acessada facilmente sem precisar criar uma página separada para cada uma.

Diagrama de estrutura de arquivos exibido em um fundo escuro. A estrutura começa com a pasta "app", que contém a pasta "docs". Dentro da pasta "docs", há uma subpasta chamada "[...slug]" que contém o arquivo "page.tsx". Além disso, dentro da pasta "app", há dois arquivos: "layout.tsx" e "page.tsx".

Alguns casos de uso comuns para o uso do catch-all

Sites de Receitas: Você tem várias categorias e subcategorias (como /receitas/italiana/pasta, /receitas/brasileira/feijoada). Usando segmentos catch-all, um único componente pode lidar com todas essas variações.

Aplicativos de Viagens: Imagine um site onde as URLs são estruturadas como /viagens/europa/franca/paris ou /viagens/america/brazil/rio-de-janeiro. Com segmentos catch-all, você pode usar um único arquivo para renderizar qualquer combinação de continente, país e cidade.

Portais de Educação: Para um site educacional com URLs como /cursos/programacao/javascript ou /cursos/design/grafico, segmentos catch-all permitem lidar com todas essas rotas de maneira eficiente.

Conclusão

O roteamento é uma parte integral do desenvolvimento web, permitindo que os usuários naveguem entre diferentes páginas dentro de uma aplicação. O Next.js simplifica o roteamento por meio de seu mecanismo baseado no sistema de arquivos.

Nós exploramos o básico do roteamento no Next.js 14, focando especificamente no App Router introduzido na versão mais recente.

Discutimos convenções de roteamento, criamos rotas para diferentes cenários e destacamos a abordagem de convenção sobre configuração do Next.js para roteamento.

Com o Next.js, você pode definir e gerenciar rotas facilmente aproveitando a estrutura de arquivos e pastas da sua base de código, eliminando a necessidade de configuração adicional de roteamento.

Se você quiser mergulhar ainda mais fundo, que tal conhecer a Formação Next.js 14: desenvolvendo aplicações robustas com alta produtividade, aqui da Alura?

Nessa formação, você, a Patrícia Silva e eu vamos desenvolver aplicações e nos aprofundar nesse Framework que é super utilizado no universo do React!

Vinicios Neves
Vinicios Neves

Vinicios Neves, Tech Lead e Educador, mistura código e didática há mais de uma década. Especialista em TypeScript, lidera equipes full-stack em Lisboa e inspira futuros desenvolvedores na FIAP e Alura. Com um pé no código e outro no ensino, ele prova que a verdadeira engenharia de software vai além das linhas de código. Além de, claro, ser senior em falar que depende.

Veja outros artigos sobre Front-end