Português

Explore a API unstable_cache do Next.js para um controle detalhado sobre o cache de dados, melhorando o desempenho e a experiência do usuário em aplicações dinâmicas.

Cache Instável do Next.js: Controle Detalhado de Cache para Aplicações Dinâmicas

O Next.js revolucionou o desenvolvimento web, oferecendo recursos poderosos para construir aplicações performáticas e escaláveis. Um de seus pontos fortes é seu robusto mecanismo de cache, que permite aos desenvolvedores otimizar a busca e a renderização de dados para uma experiência de usuário mais fluida. Embora o Next.js forneça várias estratégias de cache, a API unstable_cache oferece um novo nível de controle detalhado, permitindo que os desenvolvedores personalizem o comportamento do cache para as necessidades específicas de suas aplicações dinâmicas. Este artigo explora a API unstable_cache, suas capacidades, benefícios e aplicações práticas.

Entendendo o Cache no Next.js

Antes de mergulhar no unstable_cache, é essencial entender as diferentes camadas de cache no Next.js. O Next.js utiliza vários mecanismos de cache para melhorar o desempenho:

Embora esses mecanismos de cache sejam poderosos, eles podem nem sempre fornecer o nível de controle necessário para aplicações complexas e dinâmicas. É aqui que o unstable_cache entra em cena.

Apresentando a API `unstable_cache`

A API unstable_cache no Next.js permite que os desenvolvedores definam estratégias de cache personalizadas para operações individuais de busca de dados. Ela fornece controle detalhado sobre:

A API é considerada "instável" porque ainda está em desenvolvimento e pode sofrer alterações em versões futuras do Next.js. No entanto, ela oferece funcionalidades valiosas para cenários de cache avançados.

Como o `unstable_cache` Funciona

A função unstable_cache recebe dois argumentos principais:

  1. Uma função que busca ou computa os dados: Esta função realiza a recuperação ou o cálculo real dos dados.
  2. Um objeto de opções: Este objeto especifica as opções de cache, como TTL, tags e chave.

Aqui está um exemplo básico de como usar o unstable_cache:

import { unstable_cache } from 'next/cache';

async function getData(id: string) {
  return unstable_cache(
    async () => {
      // Simula a busca de dados de uma API
      await new Promise((resolve) => setTimeout(resolve, 1000));
      const data = { id: id, value: `Data for ID ${id}` };
      return data;
    },
    ["data", id],
    { tags: ["data", `item:${id}`] }
  )();
}

export default async function Page({ params }: { params: { id: string } }) {
  const data = await getData(params.id);
  return 
{data.value}
; }

Neste exemplo:

Principais Funcionalidades e Opções do `unstable_cache`

1. Tempo de Vida (TTL)

A opção revalidate (anteriormente `ttl` em versões experimentais anteriores) especifica o tempo máximo (em segundos) que os dados em cache são considerados válidos. Após esse tempo, o cache é revalidado na próxima solicitação.

import { unstable_cache } from 'next/cache';

async function getData(id: string) {
  return unstable_cache(
    async () => {
      // Simula a busca de dados de uma API
      await new Promise((resolve) => setTimeout(resolve, 1000));
      const data = { id: id, value: `Data for ID ${id}` };
      return data;
    },
    ["data", id],
    { tags: ["data", `item:${id}`], revalidate: 60 } // Cache por 60 segundos
  )();
}

Neste exemplo, os dados serão armazenados em cache por 60 segundos. Após 60 segundos, a próxima solicitação acionará uma revalidação, buscando dados novos da API e atualizando o cache.

Consideração Global: Ao definir valores de TTL, considere a frequência das atualizações de dados. Para dados que mudam com frequência, um TTL mais curto é apropriado. Para dados relativamente estáticos, um TTL mais longo pode melhorar significativamente o desempenho.

2. Tags de Cache

As tags de cache permitem agrupar dados em cache relacionados e invalidá-los coletivamente. Isso é útil quando atualizações em um dado afetam outros dados relacionados.

import { unstable_cache, revalidateTag } from 'next/cache';

async function getProduct(id: string) {
  return unstable_cache(
    async () => {
      // Simula a busca de dados do produto de uma API
      await new Promise((resolve) => setTimeout(resolve, 500));
      const product = { id: id, name: `Product ${id}`, price: Math.random() * 100 };
      return product;
    },
    ["product", id],
    { tags: ["products", `product:${id}`] }
  )();
}

async function getCategoryProducts(category: string) {
  return unstable_cache(
    async () => {
      // Simula a busca de produtos por categoria de uma API
      await new Promise((resolve) => setTimeout(resolve, 500));
      const products = Array.from({ length: 3 }, (_, i) => ({ id: `${category}-${i}`, name: `Product ${category}-${i}`, price: Math.random() * 100 }));
      return products;
    },
    ["categoryProducts", category],
    { tags: ["products", `category:${category}`] }
  )();
}

// Invalida o cache para todos os produtos e um produto específico
async function updateProduct(id: string, newPrice: number) {
  // Simula a atualização do produto no banco de dados
  await new Promise((resolve) => setTimeout(resolve, 500));

  // Invalida o cache para o produto e a categoria de produtos
  revalidateTag("products");
  revalidateTag(`product:${id}`);

  return { success: true };
}

Neste exemplo:

Consideração Global: Use nomes de tags significativos e consistentes. Considere criar uma estratégia de tagueamento que se alinhe com seu modelo de dados.

3. Geração de Chave de Cache

A chave de cache é usada para identificar dados em cache. Por padrão, unstable_cache gera uma chave com base nos argumentos passados para a função. No entanto, você pode personalizar o processo de geração de chave usando o segundo argumento para `unstable_cache`, que é um array que atua como uma chave. Quando qualquer um dos itens no array muda, o cache é invalidado.

import { unstable_cache } from 'next/cache';

async function getData(userId: string, sortBy: string) {
  return unstable_cache(
    async () => {
      // Simula a busca de dados de uma API
      await new Promise((resolve) => setTimeout(resolve, 1000));
      const data = { userId: userId, sortBy: sortBy, value: `Data for user ${userId}, sorted by ${sortBy}` };
      return data;
    },
    [userId, sortBy],
    { tags: ["user-data", `user:${userId}`] }
  )();
}

Neste exemplo, a chave de cache é baseada nos parâmetros userId e sortBy. Isso garante que o cache seja invalidado quando qualquer um desses parâmetros mudar.

Consideração Global: Garanta que sua estratégia de geração de chave de cache seja consistente e leve em conta todos os fatores relevantes que afetam os dados. Considere usar uma função de hash para criar uma chave única a partir de estruturas de dados complexas.

4. Revalidação Manual

A função `revalidateTag` permite invalidar manualmente o cache para dados associados a tags específicas. Isso é útil quando você precisa atualizar o cache em resposta a eventos que não são acionados diretamente por uma solicitação do usuário, como um trabalho em segundo plano ou um webhook.

import { revalidateTag } from 'next/cache';

async function handleWebhook(payload: any) {
  // Processa o payload do webhook

  // Invalida o cache para dados relacionados
  revalidateTag("products");
  revalidateTag(`product:${payload.productId}`);
}

Consideração Global: Use a revalidação manual estrategicamente. A invalidação excessiva pode anular os benefícios do cache, enquanto a sub-invalidação pode levar a dados desatualizados.

Casos de Uso Práticos para o `unstable_cache`

1. Conteúdo Dinâmico com Atualizações Infrequentes

Para sites com conteúdo dinâmico que não muda com muita frequência (por exemplo, posts de blog, artigos de notícias), você pode usar unstable_cache com um TTL mais longo para armazenar os dados em cache por períodos prolongados. Isso reduz a carga no seu backend e melhora os tempos de carregamento da página.

2. Dados Específicos do Usuário

Para dados específicos do usuário (por exemplo, perfis de usuário, carrinhos de compras), você pode usar unstable_cache com chaves de cache que incluem o ID do usuário. Isso garante que cada usuário veja seus próprios dados e que o cache seja invalidado quando os dados do usuário mudarem.

3. Dados em Tempo Real com Tolerância a Dados Desatualizados

Para aplicações que exibem dados em tempo real (por exemplo, cotações de ações, feeds de mídia social), você pode usar unstable_cache com um TTL curto para fornecer atualizações quase em tempo real. Isso equilibra a necessidade de dados atualizados com os benefícios de desempenho do cache.

4. Testes A/B

Durante os testes A/B, é importante armazenar em cache a variante do experimento atribuída a um usuário para garantir uma experiência consistente. O `unstable_cache` pode ser usado para armazenar em cache a variante selecionada usando o ID do usuário como parte da chave de cache.

Benefícios de Usar o `unstable_cache`

Considerações e Melhores Práticas

`unstable_cache` vs. Cache da API `fetch`

O Next.js também oferece recursos de cache integrados através da API fetch. Por padrão, o Next.js armazena automaticamente em cache os resultados das solicitações fetch. No entanto, o unstable_cache oferece mais flexibilidade e controle do que o cache da API fetch.

Aqui está uma comparação das duas abordagens:

Funcionalidade `unstable_cache` API `fetch`
Controle sobre o TTL Explicitamente configurável com a opção revalidate. Gerenciado implicitamente pelo Next.js, mas pode ser influenciado com a opção revalidate nas opções do fetch.
Tags de Cache Suporta tags de cache para invalidar dados relacionados. Sem suporte nativo para tags de cache.
Personalização da Chave de Cache Permite personalizar a chave de cache com um array de valores que são usados para construir a chave. Opções de personalização limitadas. A chave é derivada da URL do fetch.
Revalidação Manual Suporta revalidação manual com revalidateTag. Suporte limitado para revalidação manual.
Granularidade do Cache Permite o cache de operações de busca de dados individuais. Focado principalmente no cache de respostas HTTP.

Em geral, use o cache da API fetch para cenários simples de busca de dados onde o comportamento de cache padrão é suficiente. Use unstable_cache para cenários mais complexos onde você precisa de controle detalhado sobre o comportamento do cache.

O Futuro do Cache no Next.js

A API unstable_cache representa um passo importante nas capacidades de cache do Next.js. À medida que a API evolui, podemos esperar ver recursos ainda mais poderosos e maior flexibilidade no gerenciamento do cache de dados. Manter-se atualizado com os últimos desenvolvimentos no cache do Next.js é crucial para construir aplicações de alto desempenho e escaláveis.

Conclusão

A API unstable_cache do Next.js oferece aos desenvolvedores um controle sem precedentes sobre o cache de dados, permitindo-lhes otimizar o desempenho e a experiência do usuário em aplicações dinâmicas. Ao entender as funcionalidades e os benefícios do unstable_cache, você pode aproveitar seu poder para construir aplicações web mais rápidas, escaláveis e responsivas. Lembre-se de considerar cuidadosamente sua estratégia de cache, escolher valores de TTL apropriados, projetar suas chaves de cache de forma eficaz e monitorar o desempenho do seu cache para garantir resultados ótimos. Abrace o futuro do cache no Next.js e libere todo o potencial de suas aplicações web.