Fundamentos do Next.js 15

0/26 aulas0%
pratica

Criando e Utilizando Server Components (Data Fetching)

Aprenda sobre criando e utilizando server components (data fetching)

45 min
Aula 2 de 5

🚀 Criando e Utilizando Server Components (Data Fetching)

Olá, futuro desenvolvedor Next.js! 👋 Nesta aula prática, vamos mergulhar no coração do Next.js 15 e explorar os Server Components, focando em uma de suas capacidades mais poderosas: o Data Fetching. Prepare-se para buscar dados diretamente do servidor de forma eficiente e segura!

🎯 Introdução: O Poder dos Server Components no Data Fetching

No Next.js 15, com o App Router, todos os componentes são Server Components por padrão. Isso significa que eles são renderizados no servidor, antes mesmo de qualquer JavaScript ser enviado ao navegador do usuário. Essa característica abre um leque de possibilidades, especialmente quando se trata de buscar dados.

Por que Server Components são ideais para Data Fetching?

  • Segurança: Você pode acessar diretamente bancos de dados, chaves de API secretas e variáveis de ambiente sensíveis sem expô-las ao cliente.
  • Performance: A busca de dados ocorre no servidor, próximo à fonte de dados, reduzindo a latência. Além disso, o HTML já chega com os dados preenchidos, resultando em um carregamento inicial mais rápido e menos JavaScript no cliente.
  • Simplicidade: Adeus useEffect e useState para a gestão do ciclo de vida de dados! Em Server Components, você pode usar async/await diretamente, como se estivesse escrevendo um script Node.js.

Nesta aula, você aprenderá a criar Server Components que buscam dados de uma API externa e os renderizam na página. Vamos colocar a mão na massa!

🧑‍💻 Explicação Detalhada com Exemplos

Um Server Component é uma função assíncrona que pode await a resolução de Promises, como chamadas de fetch ou consultas a bancos de dados. Quando o componente é renderizado no servidor, ele espera pelos dados e, em seguida, gera o HTML correspondente, que é enviado ao navegador.

1. Componentes Assíncronos

Para buscar dados, seu componente precisa ser uma função assíncrona. Basta adicionar a palavra-chave async antes da declaração da função.

// app/produtos/page.tsx
async function ProdutosPage() {
  // ... aqui você fará o data fetching
  return (
    <div>
      <h1>Lista de Produtos</h1>
      {/* ... renderiza os produtos */}
    </div>
  );
}
 
export default ProdutosPage;

2. Buscando Dados com fetch

A API fetch é a maneira recomendada para buscar dados no Next.js. Ela é estendida com recursos de caching e revalidação, otimizando o desempenho.

// app/produtos/page.tsx
interface Produto {
  id: number;
  nome: string;
  preco: number;
}
 
async function getProdutos(): Promise<Produto[]> {
  const res = await fetch('https://api.example.com/produtos', {
    // Opções de caching:
    // 'force-cache' (padrão)
    // 'no-store' (sem cache)
    // next: { revalidate: 60 } (revalidar a cada 60 segundos)
  });
 
  if (!res.ok) {
    // Isso ativará o closest `error.js` Error Boundary
    throw new Error('Falha ao buscar produtos');
  }
 
  return res.json();
}
 
export default async function ProdutosPage() {
  const produtos = await getProdutos(); // Chama a função assíncrona
 
  return (
    <div>
      <h1>Lista de Produtos</h1>
      <ul>
        {produtos.map((produto) => (
          <li key={produto.id}>
            {produto.nome} - R${produto.preco.toFixed(2)}
          </li>
        ))}
      </ul>
    </div>
  );
}

Observações importantes:

  • Caching: Por padrão, fetch no Next.js cacheia os dados automaticamente. Isso significa que, se você chamar fetch com a mesma URL e opções em várias partes do seu código (ou em várias requisições do mesmo usuário), o Next.js pode servir os dados do cache, melhorando a performance. Você pode controlar esse comportamento com as opções cache e next: { revalidate }.
  • Tratamento de Erros: É crucial tratar erros nas suas chamadas de fetch. Se a requisição falhar (res.ok for false), lançar um erro é uma boa prática. No Next.js, isso pode ser capturado por um arquivo error.tsx próximo.

3. Data Fetching em Rotas Dinâmicas

Para buscar um item específico, você pode usar os params da rota dinâmica.

// app/produtos/[id]/page.tsx
interface Produto {
  id: number;
  nome: string;
  descricao: string;
  preco: number;
}
 
interface ProdutoPageProps {
  params: { id: string }; // O ID virá como string
}
 
async function getProduto(id: string): Promise<Produto> {
  const res = await fetch(`https://api.example.com/produtos/${id}`);
 
  if (!res.ok) {
    throw new Error('Falha ao buscar produto');
  }
 
  return res.json();
}
 
export default async function ProdutoPage({ params }: ProdutoPageProps) {
  const produto = await getProduto(params.id);
 
  return (
    <div>
      <h1>{produto.nome}</h1>
      <p>{produto.descricao}</p>
      <p>Preço: R${produto.preco.toFixed(2)}</p>
    </div>
  );
}

Neste exemplo, o id do produto é extraído de params.id e usado para construir a URL da API.

🏋️ Exercícios/Desafios Práticos

Agora é a sua vez de colocar a mão na massa! Vamos criar um pequeno blog usando Server Components para buscar posts de uma API pública.

🎯 Tarefas:

Para este exercício, usaremos a API gratuita JSONPlaceholder para simular dados de um blog.

  • 1. Crie um novo projeto Next.js 15:

    npx create-next-app@latest my-blog-app
    cd my-blog-app

    Escolha as opções padrão (TypeScript, Tailwind CSS, App Router, etc.).

  • 2. Crie uma página para listar todos os posts:

    • Dentro do diretório app, crie um novo diretório chamado posts.
    • Dentro de posts, crie um arquivo page.tsx.
    • Neste page.tsx, crie um Server Component que:
      • Busque uma lista de posts da URL https://jsonplaceholder.typicode.com/posts.
      • Exiba o title e o id de cada post em uma lista (<ul>).
      • Adicione um link para cada post, apontando para /posts/[id] (que criaremos a seguir).
    // app/posts/page.tsx (Exemplo de estrutura)
    import Link from 'next/link';
     
    interface Post {
      id: number;
      title: string;
      body: string;
    }
     
    async function getPosts(): Promise<Post[]> {
      // Implemente a busca de dados aqui
    }
     
    export default async function PostsPage() {
      const posts = await getPosts();
     
      return (
        <div className="container mx-auto p-4">
          <h1 className="text-3xl font-bold mb-6">Todos os Posts</h1>
          <ul className="space-y-4">
            {/* Mapeie e exiba os posts aqui */}
          </ul>
        </div>
      );
    }
  • 3. Crie uma página para exibir um único post:

    • Dentro do diretório app/posts, crie um novo diretório [id].
    • Dentro de [id], crie um arquivo page.tsx.
    • Neste page.tsx, crie um Server Component que:
      • Receba o id do post via params.
      • Busque os detalhes de um único post da URL https://jsonplaceholder.typicode.com/posts/[id].
      • Exiba o title e o body do post.
    // app/posts/[id]/page.tsx (Exemplo de estrutura)
    interface Post {
      id: number;
      title: string;
      body: string;
    }
     
    interface PostPageProps {
      params: { id: string };
    }
     
    async function getPost(id: string): Promise<Post> {
      // Implemente a busca de dados aqui
    }
     
    export default async function PostPage({ params }: PostPageProps) {
      const post = await getPost(params.id);
     
      return (
        <div className="container mx-auto p-4">
          <h1 className="text-3xl font-bold mb-4">{post.title}</h1>
          <p className="text-gray-700">{post.body}</p>
        </div>
      );
    }
  • 4. Teste suas páginas:

    • Inicie o servidor de desenvolvimento: npm run dev ou yarn dev.
    • Acesse http://localhost:3000/posts para ver a lista de posts.
    • Clique em um post ou navegue diretamente para http://localhost:3000/posts/1 (ou qualquer outro ID) para ver os detalhes de um post específico.
  • 5. (Bônus) Adicione um tratamento de erro básico:

    • Modifique suas funções getPosts e getPost para verificar res.ok e lançar um Error se a requisição falhar.
    • (Desafio extra) Crie um arquivo error.tsx dentro de app/posts para capturar e exibir erros de forma amigável.

📝 Resumo e Próximos Passos

Parabéns! 🎉 Você acabou de criar seus primeiros Server Components que buscam dados de forma eficiente e segura. Você viu como:

  • Server Components são o padrão no App Router e rodam no servidor.
  • async/await simplifica o data fetching, eliminando a necessidade de hooks de estado para dados.
  • fetch é a API principal para buscar dados, com caching integrado.
  • Rotas dinâmicas ([id]) permitem buscar dados específicos com base nos parâmetros da URL.

Na próxima aula, exploraremos os Client Components e entenderemos quando e como utilizá-los, especialmente para interatividade e estado no navegador. Veremos também como combinar Server e Client Components para construir aplicações robustas e performáticas.

Até lá, continue experimentando com o data fetching em Server Components! 🚀

© 2025 Escola All Dev. Todos os direitos reservados.

Criando e Utilizando Server Components (Data Fetching) - Fundamentos do Next.js 15 | escola.all.dev.br