Pular para o conteúdo
🎯 Aula 03

🚀 App Router - Fundamentos

Domine o novo sistema de roteamento do Next.js 13+ baseado em Server Components e aprenda como ele revoluciona o desenvolvimento web.

25 minutos
Nível:Iniciante

Por que isso é importante

O App Router é 70% mais rápido que o Pages Router tradicional e permite Server Components nativos, resultando em 50% menos JavaScript enviado ao cliente. Aplicações App Router carregam 2x mais rápido e têm melhor SEO, sendo adotado por 85% dos novos projetos Next.js.

Conceitos Fundamentais do App Router

Server Components (RSC):

Componentes que renderizam no servidor, reduzindo bundle JS e melhorando performance. Padrão no App Router.

Client Components:

Componentes que rodam no cliente, usando 'use client'. Necessários para interatividade, hooks e APIs do browser.

Nested Layouts:

Layouts aninhados que persistem entre navegações, mantendo estado e evitando re-renders desnecessários.

Streaming & Suspense:

Renderização progressiva com loading states, permitindo carregamento parcial de componentes pesados.

App Router vs Pages Router

📊 Comparação🚀 App Router📄 Pages Router
comparison

✅ App Router (Recomendado)

  • Server Components nativos
  • Streaming e Suspense
  • Layouts aninhados com persistência
  • Loading & Error states automáticos
  • Server Actions (formulários sem JS)
  • Bundle JS menor (até 50%)

📄 Pages Router (Legacy)

  • Client Components por padrão
  • getServerSideProps / getStaticProps
  • Layout único com _app.tsx
  • Loading manual em cada página
  • API Routes tradicionais
  • Bundle JS maior
app-router

🚀 Estrutura do App Router

Estrutura de pastas
src/app/
├── globals.css          # Estilos globais
├── layout.tsx          # Layout raiz (obrigatório)
├── page.tsx            # Página inicial (/)
├── loading.tsx         # Loading UI
├── error.tsx           # Error UI
├── not-found.tsx       # 404 UI
│
├── dashboard/          # Rota /dashboard
│   ├── layout.tsx      # Layout do dashboard
│   ├── page.tsx        # /dashboard
│   ├── loading.tsx     # Loading do dashboard
│   │
│   └── settings/       # Rota /dashboard/settings
│       ├── page.tsx    # /dashboard/settings
│       └── loading.tsx # Loading das settings
│
└── api/               # API Routes
    └── users/
        └── route.ts   # GET/POST /api/users

✅ Vantagens Principais

  • Co-location: Loading e error states ficam próximos às páginas
  • Layouts aninhados: Múltiplos layouts que persistem na navegação
  • Streaming automático: Carregamento progressivo sem configuração
  • Server Components: Menos JavaScript no cliente
pages-router

📄 Estrutura do Pages Router (Legacy)

Estrutura de pastas
src/pages/
├── _app.tsx            # Layout global
├── _document.tsx       # HTML document
├── index.tsx           # Página inicial (/)
├── 404.tsx             # Página 404
│
├── dashboard/          # Rota /dashboard
│   ├── index.tsx       # /dashboard
│   └── settings.tsx    # /dashboard/settings
│
└── api/               # API Routes
    └── users.ts       # GET/POST /api/users

⚠️ Limitações

  • Um layout apenas: Definido em _app.tsx
  • Client-side por padrão: Mais JavaScript no cliente
  • Loading manual: Cada página precisa implementar
  • Data fetching complexo: getServerSideProps/getStaticProps

Server vs Client Components

🏗️ Server Components (Padrão)

Renderizam no servidor, reduzindo o bundle JavaScript enviado ao cliente.

src/app/page.tsx
// Server Component (padrão no App Router)
// Sem 'use client' = Server Component

export default async function HomePage() {
  // ✅ Pode fazer fetch diretamente
  const posts = await fetch('https://api.example.com/posts')
    .then(res => res.json());

  // ✅ Pode acessar variáveis de ambiente secretas
  const secret = process.env.DATABASE_SECRET;

  return (
    <div>
      <h1>Meu Blog</h1>
      {posts.map(post => (
        <article key={post.id}>
          <h2>{post.title}</h2>
          <p>{post.content}</p>
        </article>
      ))}
    </div>
  );
}

✅ Quando usar:

  • • Buscar dados
  • • Acessar APIs backend
  • • Renderizar conteúdo estático
  • • SEO importante

💻 Client Components

Renderizam no cliente, necessários para interatividade e hooks do React.

src/components/Counter.tsx
'use client'; // ← Diretiva obrigatória

import { useState } from 'react';

export default function Counter() {
  // ✅ Pode usar hooks do React
  const [count, setCount] = useState(0);

  // ✅ Pode usar APIs do browser
  const handleClick = () => {
    setCount(count + 1);
    // ✅ Pode usar localStorage, window, etc.
    localStorage.setItem('count', count.toString());
  };

  return (
    <div>
      <p>Contador: {count}</p>
      {/* ✅ Pode usar event handlers */}
      <button onClick={handleClick}>
        Incrementar
      </button>
    </div>
  );
}

✅ Quando usar:

  • • Interatividade (onClick, onChange)
  • • Hooks do React (useState, useEffect)
  • • APIs do browser (localStorage, window)
  • • Bibliotecas client-side

Exemplo Prático: Blog com App Router

Vamos criar um blog simples que demonstra os conceitos do App Router:

1️⃣ Layout Raiz

src/app/layout.tsx
import Link from 'next/link';
import './globals.css';
import type { Metadata } from 'next';

export const metadata: Metadata = {
  title: 'Meu Blog',
  description: 'Blog criado com Next.js App Router',
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="pt-BR">
      <body>
        <header className="bg-bg-2 text-foreground p-4">
          <h1>Meu Blog</h1>
          <nav>
            <Link href="/">Home</Link>
            <Link href="/blog">Blog</Link>
            <Link href="/sobre">Sobre</Link>
          </nav>
        </header>
        <main className="container mx-auto p-4">
          {children}
        </main>
        <footer className="bg-bg-2 text-foreground p-4 text-center">
          © 2025 Meu Blog
        </footer>
      </body>
    </html>
  );
}

2️⃣ Página Inicial (Server Component)

src/app/page.tsx
// Server Component - busca dados no servidor
export default async function HomePage() {
  // ✅ Fetch direto no Server Component
  const posts = await fetch('https://jsonplaceholder.typicode.com/posts?_limit=5', {
    next: { revalidate: 3600 } // Cache por 1 hora
  }).then(res => res.json());

  return (
    <div>
      <h1>Bem-vindo ao Meu Blog</h1>
      <p>Últimos posts:</p>
      
      <div className="grid gap-4">
        {posts.map((post: any) => (
          <article key={post.id} className="border p-4 rounded">
            <h2 className="text-xl font-bold">{post.title}</h2>
            <p className="text-fg-dim">{post.body.slice(0, 100)}...</p>
            <a href={`/blog/${post.id}`} className="text-blue-500">
              Ler mais →
            </a>
          </article>
        ))}
      </div>
    </div>
  );
}

3️⃣ Seção Blog com Loading

src/app/blog/loading.tsx
// Loading UI automático para /blog
export default function Loading() {
  return (
    <div className="animate-pulse">
      <div className="h-8 bg-bg-3 rounded mb-4"></div>
      <div className="space-y-4">
        {[1,2,3].map(i => (
          <div key={i} className="border p-4 rounded">
            <div className="h-6 bg-bg-3 rounded mb-2"></div>
            <div className="h-4 bg-bg-3 rounded w-3/4"></div>
          </div>
        ))}
      </div>
    </div>
  );
}

Vantagens do App Router

  • 🚀 Performance Superior:

    Server Components reduzem bundle JS em até 50%

  • 🔄 Streaming Nativo:

    Carregamento progressivo automático com Suspense

  • 🎨 Layouts Aninhados:

    Múltiplos layouts que persistem na navegação

  • ⚡ Loading States:

    UI de carregamento automática para cada rota

  • 🛡️ Error Boundaries:

    Tratamento de erro granular por rota

  • 📊 SEO Melhorado:

    Server Components melhoram indexação

O que Você Conquistou

🎉 Fantástico! Você agora domina os fundamentos do App Router e entende como ele revoluciona o desenvolvimento Next.js.

  • Diferenças fundamentais entre App Router e Pages Router
  • Server vs Client Components e quando usar cada um
  • Arquivos especiais (layout, page, loading, error)
  • Streaming e Suspense para carregamento progressivo
  • Exemplo prático de blog com App Router