Fundamentos do Next.js 15
Entendendo a Estrutura de Pastas e o App Router
Aprenda sobre entendendo a estrutura de pastas e o app router
Módulo 1: Introdução e Setup do Next.js 15 - Aula: Entendendo a Estrutura de Pastas e o App Router
Olá e seja bem-vindo(a) à primeira aula teórica do nosso curso de Fundamentos do Next.js 15! 🎉
Nesta aula, vamos mergulhar no coração de como o Next.js 15 organiza suas aplicações: o App Router. Ele representa uma mudança fundamental em relação às versões anteriores (que usavam o Pages Router) e é essencial para construir aplicações modernas, performáticas e escaláveis com Next.js.
Compreender a estrutura de pastas e os arquivos especiais do App Router é o primeiro passo para dominar o desenvolvimento com Next.js 15. Vamos lá!
1. Introdução ao App Router ✨
O App Router, introduzido no Next.js 13 e agora o padrão no Next.js 15, é construído sobre os React Server Components. Ele oferece uma abordagem mais flexível e poderosa para o roteamento e a renderização, permitindo que você crie layouts aninhados, estados de carregamento instantâneos, tratamento de erros robusto e muito mais, tudo isso com um foco na performance.
A principal filosofia do App Router é que a estrutura de pastas dentro do diretório app define as rotas da sua aplicação. Cada pasta representa um segmento de URL, e arquivos especiais dentro dessas pastas definem a UI (User Interface) para essa rota.
Por que o App Router? 🤔
- Server Components por padrão: Melhor performance, menor JavaScript enviado ao cliente.
- Nested Layouts: Layouts complexos que podem ser aninhados e compartilhados entre rotas.
- Streaming: Carrega partes da UI progressivamente, melhorando a percepção de performance.
- Data Fetching simplificado:
async/awaitdiretamente nos componentes. - Ferramentas de UI de carregamento e erro: Estados de carregamento e tratamento de erros declarativos.
2. Entendendo a Estrutura de Pastas e Arquivos Especiais 📁
Dentro do diretório app, a estrutura de pastas é o mapa da sua aplicação. Vamos explorar os arquivos e convenções mais importantes.
app/
├── (auth)/
│ ├── login/
│ │ └── page.tsx
│ └── layout.tsx
├── dashboard/
│ ├── layout.tsx
│ ├── page.tsx
│ ├── settings/
│ │ └── page.tsx
│ ├── analytics/
│ │ └── page.tsx
│ └── loading.tsx
├── _components/
│ └── Button.tsx
├── api/
│ └── users/
│ └── route.ts
├── layout.tsx
├── page.tsx
├── global-error.tsx
└── not-found.tsx
2.1. Arquivos Essenciais para Rotas 🛣️
page.tsx (ou .js, .jsx)
- Propósito: Define a interface de usuário única de uma rota e a torna publicamente acessível.
- Localização: Deve estar dentro de uma pasta de rota.
- Exemplo:
app/dashboard/page.tsxcorresponde à rota/dashboard.app/page.tsxé a rota raiz (/).
// app/dashboard/page.tsx
export default function DashboardPage() {
return (
<main>
<h1>Bem-vindo ao Dashboard!</h1>
<p>Este é o conteúdo principal da sua página.</p>
</main>
);
}layout.tsx (ou .js, .jsx)
- Propósito: Define a interface de usuário compartilhada para um segmento de rota e seus filhos. Um layout envolve os
page.tsxe outroslayout.tsxaninhados. - Localização: Pode estar em qualquer pasta de rota, incluindo a pasta
appraiz. - Características:
- Recebe uma prop
childrenque será preenchida com os componentes de rota filhos (outros layouts ou páginas). - Não re-renderiza quando a navegação ocorre entre páginas que compartilham o mesmo layout.
- É um Server Component por padrão.
- O
layout.tsxraiz (app/layout.tsx) é obrigatório e deve definir as tags<html>e<body>.
- Recebe uma prop
// app/layout.tsx (Layout Raiz)
import './globals.css'; // Importa estilos globais
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="pt-BR">
<body>{children}</body>
</html>
);
}// app/dashboard/layout.tsx (Layout Aninhado)
import Navbar from '../_components/Navbar'; // Exemplo de componente compartilhado
export default function DashboardLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<section>
<Navbar /> {/* Componente de navegação para o dashboard */}
<aside>
<p>Menu Lateral do Dashboard</p>
{/* ... links de navegação do dashboard */}
</aside>
<main>{children}</main> {/* Aqui será renderizado o page.tsx ou outros layouts aninhados */}
</section>
);
}2.2. Arquivos para UI de Carregamento e Erro ⏳⚠️
loading.tsx (ou .js, .jsx)
- Propósito: Exibe um estado de carregamento instantâneo enquanto o conteúdo de uma rota está sendo carregado.
- Localização: Dentro de uma pasta de rota.
- Características:
- É automaticamente envolvido pelo
layout.tsxpai. - Ajuda a melhorar a experiência do usuário, fornecendo feedback visual.
- É automaticamente envolvido pelo
// app/dashboard/loading.tsx
export default function Loading() {
return (
<div className="loading-spinner">
<h2>Carregando Dashboard...</h2>
{/* Você pode adicionar um spinner ou qualquer UI de carregamento aqui */}
</div>
);
}error.tsx (ou .js, .jsx)
- Propósito: Cria um limite de erro para uma rota, capturando erros em seus filhos e exibindo uma UI de fallback.
- Localização: Dentro de uma pasta de rota.
- Características:
- Recebe as props
error(o objeto de erro) ereset(uma função para tentar renderizar o conteúdo novamente). - É um Client Component por padrão (precisa da diretiva
'use client').
- Recebe as props
// app/dashboard/error.tsx
'use client'; // Error components must be Client Components
import { useEffect } from 'react';
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
// Log the error to an error reporting service
console.error(error);
}, [error]);
return (
<div>
<h2>Algo deu errado!</h2>
<p>{error.message}</p>
<button
onClick={
// Attempt to recover by trying to re-render the segment
() => reset()
}
>
Tentar novamente
</button>
</div>
);
}not-found.tsx (ou .js, .jsx)
- Propósito: Exibe uma UI personalizada quando a rota não é encontrada.
- Localização: Pode ser definida no nível da rota (
app/dashboard/not-found.tsx) ou no nível raiz (app/not-found.tsx). - Características:
- Substitui a página 404 padrão do Next.js.
- Para acioná-lo, você pode usar a função
notFound()do Next.js em um Server Component.
// app/not-found.tsx
import Link from 'next/link';
export default function NotFound() {
return (
<div>
<h2>Página Não Encontrada</h2>
<p>Não foi possível encontrar o recurso solicitado.</p>
<Link href="/">Voltar para a Home</Link>
</div>
);
}global-error.tsx (ou .js, .jsx)
- Propósito: Um limite de erro global que captura erros em todos os layouts e páginas, incluindo o
layout.tsxraiz. - Localização: Apenas na pasta
appraiz. - Características:
- Deve ser um Client Component (
'use client'). - Substitui o
<html>e<body>do layout raiz quando um erro ocorre.
- Deve ser um Client Component (
// app/global-error.tsx
'use client';
export default function GlobalError({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
return (
<html>
<body>
<h2>Algo deu muito errado globalmente!</h2>
<p>{error.message}</p>
<button onClick={() => reset()}>Tentar novamente</button>
</body>
</html>
);
}2.3. Outros Arquivos Especiais e Convenções 🧩
template.tsx (ou .js, .jsx)
- Propósito: Semelhante a um
layout.tsx, mas seus filhos re-renderizam em cada navegação. - Localização: Dentro de uma pasta de rota.
- Características:
- Útil para lógicas que dependem de estado por rota, como animações de entrada/saída.
- Recebe a prop
children.
// app/dashboard/template.tsx
import React from 'react';
export default function DashboardTemplate({ children }: { children: React.ReactNode }) {
console.log('Template do Dashboard renderizado!');
return (
<div>
{/* Este div será re-renderizado em cada navegação dentro do dashboard */}
{children}
</div>
);
}default.tsx (ou .js, .jsx)
- Propósito: Fornece uma UI de fallback para Parallel Routes quando o slot de rota correspondente não está ativo.
- Localização: Dentro de um slot de rota paralela (ex:
app/@modal/default.tsx). - Características:
- Não é tão comum para iniciantes, mas é poderoso para layouts complexos com múltiplos slots de conteúdo.
route.ts (ou .js, .jsx, .mjs)
- Propósito: Cria um endpoint de API (uma rota de API) dentro do App Router.
- Localização: Dentro de uma pasta de rota.
- Características:
- Permite definir manipuladores para métodos HTTP (GET, POST, PUT, DELETE, etc.).
- Substitui o diretório
pages/apido Pages Router.
// app/api/hello/route.ts
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
return NextResponse.json({ message: 'Olá do App Router API!' });
}
export async function POST(request: Request) {
const data = await request.json();
return NextResponse.json({ received: data, status: 'success' }, { status: 200 });
}middleware.ts (ou .js)
- Propósito: Permite executar código antes que uma requisição seja concluída, modificando a requisição ou resposta.
- Localização: Na raiz do projeto (
/middleware.ts) ou dentro desrc/middleware.ts. - Características:
- É executado no Edge Runtime (ambiente de execução global e de baixa latência).
- Pode ser usado para autenticação, redirecionamentos, modificação de headers, etc.
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const currentUser = request.cookies.get('currentUser')?.value;
if (currentUser && request.nextUrl.pathname.startsWith('/auth')) {
return NextResponse.redirect(new URL('/dashboard', request.url));
}
if (!currentUser && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/auth/login', request.url));
}
}
export const config = {
matcher: ['/((?!api|_next/static|_next/image|.*\\.png$).*)'],
};2.4. Convenções de Pastas 📦
(folder) - Route Groups (Grupos de Rotas)
- Propósito: Organizar rotas em grupos lógicos sem afetar o caminho da URL.
- Exemplo:
app/(marketing)/about/page.tsxainda será acessível em/about. - Características:
- Útil para separar partes da aplicação com layouts diferentes (ex:
(auth),(dashboard),(marketing)). - Permite que vários layouts raiz existam na mesma pasta
app.
- Útil para separar partes da aplicação com layouts diferentes (ex:
app/
├── (marketing)/
│ ├── layout.tsx // Layout para rotas de marketing
│ └── about/
│ └── page.tsx // Rota: /about
├── (shop)/
│ ├── layout.tsx // Layout para rotas da loja
│ └── products/
│ └── page.tsx // Rota: /products
└── page.tsx // Rota: /
_folder - Pastas Privadas
- Propósito: Pastas que não são rotas e não devem ser acessíveis publicamente.
- Exemplo:
app/_components,app/_lib,app/_utils. - Características:
- Útil para armazenar componentes reutilizáveis, funções utilitárias, hooks, etc.
- O Next.js ignora pastas que começam com
_ao criar rotas.
app/
├── dashboard/
│ └── page.tsx
├── _components/
│ └── Header.tsx
│ └── Footer.tsx
├── _utils/
│ └── helpers.ts
└── page.tsx
3. Server Components vs. Client Components 🔄
Um conceito fundamental no App Router é a distinção entre Server Components e Client Components.
-
Server Components (Padrão):
- Renderizados no servidor.
- Não podem usar hooks de React como
useState,useEffect, ouuseContext. - Não têm acesso ao DOM ou eventos do navegador.
- Podem acessar diretamente o sistema de arquivos ou bancos de dados (APIs de servidor).
- Não adicionam JavaScript ao bundle do cliente, resultando em carregamentos mais rápidos.
- Podem ser
asyncpara data fetching.
-
Client Components:
- Renderizados no cliente (no navegador).
- Podem usar hooks de React, eventos do navegador e acessar o DOM.
- São interativos.
- Para definir um Client Component, adicione a diretiva
'use client'no topo do arquivo.
// app/dashboard/page.tsx (Server Component por padrão)
// Pode ser async para buscar dados
async function getPosts() {
const res = await fetch('https://api.example.com/posts');
return res.json();
}
export default async function DashboardPage() {
const posts = await getPosts(); // Data fetching diretamente no Server Component
return (
<div>
<h1>Meus Posts</h1>
<ul>
{posts.map((post: any) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
{/* Um Client Component pode ser importado aqui */}
<InteractiveButton />
</div>
);
}// app/_components/InteractiveButton.tsx (Client Component)
'use client'; // <-- Esta diretiva o torna um Client Component
import { useState } from 'react';
export default function InteractiveButton() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Você clicou {count} vezes!
</button>
);
}4. Resumo e Próximos Passos 🚀
Nesta aula, exploramos a estrutura de pastas e os arquivos especiais que compõem o App Router do Next.js 15. Você aprendeu que:
- O diretório
appé a base do App Router. - Pastas definem segmentos de URL.
page.tsxtorna uma rota acessível e define sua UI única.layout.tsxdefine UI compartilhada e pode ser aninhado.loading.tsxeerror.tsxfornecem feedback visual e tratamento de erros.not-found.tsxeglobal-error.tsxlidam com rotas não encontradas e erros globais.route.tscria endpoints de API.middleware.tsintercepta requisições.()(Route Groups) e_(Pastas Privadas) ajudam na organização.- A distinção entre Server Components (padrão) e Client Components (
'use client') é crucial para a performance e interatividade.
Com essa base sólida, você está pronto para começar a construir suas primeiras rotas e componentes no Next.js 15. Na próxima aula, vamos colocar a mão na massa e configurar nosso ambiente de desenvolvimento para iniciar um novo projeto Next.js!
Próximos Passos:
- Módulo 1 - Aula 2: Setup do Ambiente de Desenvolvimento e Criação do Primeiro Projeto Next.js 15.
Até lá! 👋