logo

NaranjaLabs

Post

Como revalidar páginas estáticas no Next.js usando ISR

Fullstack

profile

Mateus Meneses

19/05/2023

O Next.js é um framework popular para desenvolvimento web que oferece suporte à geração de páginas estáticas. No entanto, surge uma problemática quando uma página estática precisa ser modificada. Por exemplo, em um cenário de e-commerce, pode ocorrer uma atualização de preço de um produto após a geração da página estática em tempo de compilação. Para lidar com esse desafio, o Next.js oferece uma solução poderosa: a Renderização de Páginas Estáticas Incrementais (ISR).

O ISR (Incremental Static Regeneration) permite que as páginas estáticas sejam revalidadas e atualizadas de forma eficiente, mesmo após a geração inicial. Com o ISR, é possível definir um tempo de revalidação para cada página estática, determinando com que frequência o Next.js deve buscar atualizações nos dados da página. Dessa forma, se um preço de produto for atualizado no back-end, por exemplo, a página estática correspondente será revalidada no servidor, trazendo a informação atualizada para o cliente sem a necessidade de reconstruir todas as páginas. Mas imagine só a grande problemática! Você atualizou o preço do produto do seu e-commerce, mas o front-end será revalidado apenas após alguns segundos, minutos ou horas a depender de como está a configuração de revalidação, por isso o Next.js 13 oferece outras formas de revalidação! Vamos aprender sobre elas.

Imagem da Publicação

Para aprender sobre cada validação, vamos utilizar o clássico exemplo da construção de um blog! Nesse blog, vamos trabalhar na página principal, onde todos os artigos são apresentados. Em nossa página do blog, faremos duas requisições principais: as publicações e os autores. Segue o código da página:

1import Card from '@/components/Card';
2
3export default async function Home() {
4  const data = await fetch('https://jsonplaceholder.typicode.com/posts');
5  const requestAuthors = await fetch('http://localhost:3000/api/authors');
6  const authors = await requestAuthors.json();
7  const posts = await data.json();
8  return (
9    <main className='px-16 py-12'>
10      <h1 className='font-black text-4xl'>Autores</h1>
11      <div className='mt-4 flex justify-center gap-24'>
12        {authors.map((author: any) => (
13          <Card
14            key={author.name}
15            title={author.name}
16            body={author.desc}
17            image={author.image.src}
18          />
19        ))}
20      </div>
21      <h1 className='font-black text-4xl mt-8 mb-4'>Publicações</h1>
22      <div className='grid grid-cols-3 gap-8 place-items-center'>
23        {posts.map((post: any) => (
24          <Card key={post.id} title={post.title} body={post.body} hasButton />
25        ))}
26      </div>
27    </main>
28  );
29}
30

Agora que temos nossa página pronta, vamos seguir para a implementação da revalidação!

Revalidação Incremental

Primeira opção, podemos revalidar a página inteira após um determinado período de tempo. E isso é bem fácil! A única coisa que precisamos fazer é adicionar o seguinte trecho de código a seguir antes da implementação da função Home:

1export const revalidate = 30;

Ao exportar uma constante com esse nome, você estará dizendo ao Next.js que por trás dos panos ele precisa revalidar toda essa página toda vez que alguém acessa-la após 30s desde a última requisição. Fácil, não é?!

A partir de agora, a cada 30 segundos, quando um usuário acessar a nossa página, o Next.js irá refazer todas as requisições e então comparará os resultados com o que temos hoje, caso haja uma mudança, o usuário já receberá a página atualizada!

Vale ressaltar alguns pontos:

  • A página não é revalidada a cada 30 segundos! A página é revalidada após alguém acessa-la após 30 segundos desde a última revalidação. Pode passar 24h desde que alguém acessou, então o seu sistema não terá feito nenhuma requisição durante 24h, mesmo que os dados tenham sim mudado!
  • Após um usuário acessar e a página for revalidada, caso outro usuário acesse não será necessário fazer a reconstrução da página novamente. Todos os novos usuários já receberão a página estática atualizada!

Agora... que tal fazermos algumas observações?

As publicações podem ter necessidade de serem revalidadas com uma frequência maior, porque o Marketing não pode esperar! Mas, não é todo dia que temos um autor novo em nosso blog, não é? Considerando que não é um blog aberto, claro! Então... por que estamos revalidando os autores no mesmo tempo que as publicações? E com esse questionamento, iremos para a próxima implementação!

Revalidação na Requisição

Isso mesmo! Invés de revalidar tudo, podemos revalidar apenas a requisição específica. E para isso, novamente, é algo bem simples! Segue o trecho de código de como revalidar uma requisição:

1const data = await fetch('https://jsonplaceholder.typicode.com/posts', {next: {revalidate: 30}});


Agora nós estamos dizendo diretamente no fetch que é necessário revalidar essa requisição a cada 30s! Fácil demais!

Dessa forma podemos ter diferentes tempos de revalidação em cada requisição específica. Agora vai da sua necessidade e criatividade para utilizar essa implementação.

ON-DEMAND Revalidation

Agora sim, chegamos na implementação mais especial!

Que tal voltarmos a nossa problemática do e-commerce? Se atualizarmos o preço de um produto, mas esse produto só ser revalidado no front-end depois de 60s? Isso é o ideal? Claro que não! Em diversos casos, precisamos que a revalidação seja de imediato. E é com isso que o Next.js brilha, trazendo o On-Demand Revalidation.

Com essa implementação, podemos construir uma lógica que irá solicitar a revalidação de imediato. Como por exemplo, ao fazer uma nova publicação já solicitar a revalidação do blog. Vamos implementar em nosso blog:

Primeiro, vamos remontar um pouco a estrutura do nosso blog. Agora, realmente estamos puxando publicações reais através de um headless CMS.

1import Card from '@/components/Card';
2import { sanityQueries } from '@/lib/sanityQueries';
3
4export default async function Home() {
5  const authors = await sanityQueries.authors();
6  const posts = await sanityQueries.posts();
7
8  return (
9    <main className='px-16 py-12'>
10      <h1 className='font-black text-4xl'>Autores</h1>
11      <div className='mt-4 flex justify-center gap-24'>
12        {authors.map((author: any) => (
13          <Card
14            key={author.name}
15            title={author.name}
16            body={author.desc}
17            image={author.image}
18          />
19        ))}
20      </div>
21      <h1 className='font-black text-4xl mt-8 mb-4'>Publicações</h1>
22      <div className='grid grid-cols-3 gap-8 place-items-center'>
23        {posts.map((post: any) => (
24          <Card
25            key={post.id}
26            title={post.title}
27            body={post.body}
28            image={post.mainImage}
29            hasButton
30          />
31        ))}
32      </div>
33    </main>
34  );
35}

Ao fazer build dessa aplicação dessa forma, temos o seguinte resultado:

Imagem da Publicação

Temos um blog funcional! Mas, a problemática também esta presente! Ao adicionarmos uma nova publicação, o blog não é atualizado. Vamos começar a resolver isso??

Precisamos criar uma função que irá rodar em nosso servidor Nextjs, portanto iremos criar no seguinte caminho:

/app/api/revalidate/route.ts

1import { revalidatePath } from 'next/cache';
2import { NextRequest, NextResponse } from 'next/server';
3
4export async function GET(request: NextRequest) {
5  const path = request.nextUrl.searchParams.get('path');
6  if (!path) {
7    return NextResponse.json({ revalidate: false, message: 'Path not found' });
8  }
9  revalidatePath(path);
10  return NextResponse.json({
11    revalidate: true,
12    now: Date.now().toLocaleString('pt-br'),
13  });
14}
15

A partir de agora, temos uma função que receberá um request informando qual será o caminho (path) a ser revalidado e então fará a revalidação com o revalidatePath(path), simples! E como essa função é chamada?

Bem, tudo que precisamos fazer é acessar a url dessa forma: nossodominio/api/revalidate?path=caminho-a-ser-revalidado

Mas, nenhum usuário irá manualmente ficar acessando essa url para ter o blog atualizado, não é? Por isso, você deve pensar em como disparar essa revalidação! No nosso caso, estamos utilizando o Sanity, então podemos disparar um fetch a essa url assim que clicamos no botão "publicar" ou "editar" ou "remover". A depender da implementação do seu projeto, isso com certeza irá mudar. Mas o importante é entender a função da api!

Que tal ver em tempo real, de uma forma bem descomplicada, tudo que explicamos aqui? Veja esse vídeo: Desvendando a revalidação ISR do NextJS 13 + Sanity.

profile

Mateus Meneses

Aquele dev top