Fundamentos do Next.js 15
Criando e Utilizando Server Components (Data Fetching)
Aprenda sobre criando e utilizando server components (data fetching)
🚀 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
useEffecteuseStatepara a gestão do ciclo de vida de dados! Em Server Components, você pode usarasync/awaitdiretamente, 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,
fetchno Next.js cacheia os dados automaticamente. Isso significa que, se você chamarfetchcom 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çõescacheenext: { revalidate }. - Tratamento de Erros: É crucial tratar erros nas suas chamadas de
fetch. Se a requisição falhar (res.okforfalse), lançar um erro é uma boa prática. No Next.js, isso pode ser capturado por um arquivoerror.tsxpró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-appEscolha 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 chamadoposts. - Dentro de
posts, crie um arquivopage.tsx. - Neste
page.tsx, crie um Server Component que:- Busque uma lista de posts da URL
https://jsonplaceholder.typicode.com/posts. - Exiba o
titlee oidde cada post em uma lista (<ul>). - Adicione um link para cada post, apontando para
/posts/[id](que criaremos a seguir).
- Busque uma lista de posts da URL
// 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> ); } - Dentro do diretório
-
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 arquivopage.tsx. - Neste
page.tsx, crie um Server Component que:- Receba o
iddo post viaparams. - Busque os detalhes de um único post da URL
https://jsonplaceholder.typicode.com/posts/[id]. - Exiba o
titlee obodydo post.
- Receba o
// 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> ); } - Dentro do diretório
-
4. Teste suas páginas:
- Inicie o servidor de desenvolvimento:
npm run devouyarn dev. - Acesse
http://localhost:3000/postspara 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.
- Inicie o servidor de desenvolvimento:
-
5. (Bônus) Adicione um tratamento de erro básico:
- Modifique suas funções
getPostsegetPostpara verificarres.oke lançar umErrorse a requisição falhar. - (Desafio extra) Crie um arquivo
error.tsxdentro deapp/postspara capturar e exibir erros de forma amigável.
- Modifique suas funções
📝 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/awaitsimplifica 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! 🚀