14 pontos por xguru 2025-02-24 | 3 comentários | Compartilhar no WhatsApp
  • A direção futura do Next.js é empolgante
  • Houve questões em torno de Server Actions, mas parece haver potencial de melhora com useOptimistic e useFormStatus do React 19
    • A abordagem useFetcher do Remix também oferece uma boa DX
  • O PPR (Partial Pre-rendering) do Next.js e o novo sistema de cache granular se destacam especialmente
  • No geral, a impressão é muito positiva

The Big Picture

  • É possível ativar experimentalmente o novo sistema de cache em next.config.js
  • É possível definir perfis de cache para configurar diferentes tempos de expiração e ciclos de revalidação
// next.config.js  
const config = {  
  experimental: {  
    // Ativa o novo sistema de cache. Agora é possível usar `use cache` no código   
    dynamicIO: true,   
    // Opcional: configuração de perfis de cache   
    cacheLife: {  
      blog: {  
        stale: 3600, // manter cache no cliente: 1 hora  
        revalidate: 900, // atualizar no servidor: 15 minutos  
        expire: 86400, // vida útil máxima: 1 dia  
      },  
    },  
  },  
};  

Uso básico de use cache

  • É possível fazer cache em nível de arquivo, componente e função com a declaração "use cache"
  • Nos exemplos de código, basta adicionar use cache para aplicar cache com facilidade
  • Também é possível invalidar o cache no momento desejado usando cacheTag, revalidateTag etc.
// 1. Cache no nível de arquivo  
"use cache";  
export default function Page() {  
  return <div>Cached Page</div>;  
}  
  
// 2. Cache no nível de componente  
export async function PriceDisplay() {  
  "use cache";  
  const price = await fetchPrice();  
  return <div>${price}</div>;  
}  
  
// 3. Cache no nível de função  
export async function getData() {  
  "use cache";  
  return await db.query();  
}  

Cache baseado em tags

import { unstable_cacheTag as cacheTag, revalidateTag } from 'next/cache';  
  
// Faz cache de um grupo específico de dados  
export async function ProductList() {  
  'use cache';  
  cacheTag('products');  
  const products = await fetchProducts();  
  return <div>{products}</div>;  
}  
  
// Invalida o cache quando os dados mudam  
export async function addProduct() {  
  'use server';  
  await db.products.add(...);  
  revalidateTag('products');  
}  

Perfil de cache personalizado

  • É possível usar unstable_cacheLife para carregar os perfis de cache definidos em next.config.js
  • A política de cache é aplicada usando o nome do perfil declarado no código (ex.: "blog")
import { unstable_cacheLife as cacheLife } from "next/cache";  
  
export async function BlogPosts() {  
  "use cache";  
  cacheLife("blog"); // usa o perfil de cache de blog pré-definido  
  return await fetchPosts();  
}  

Pontos importantes que podem passar despercebidos

Geração automática de chave de cache

  • As props e os arguments do componente são incluídos automaticamente na chave de cache
  • Valores não serializáveis (como funções) são tratados na forma de “referência imutável”
export async function UserCard({ id, onDelete }) {  
  "use cache";  
  // id é incluído na chave de cache  
  // onDelete é passado, mas não afeta o cache  
  const user = await fetchUser(id);  
  return <div onClick={onDelete}>{user.name}</div>;  
}  

Mistura de conteúdo dinâmico e conteúdo em cache

  • É possível combinar ambos passando conteúdo dinâmico como filho dentro de conteúdo em cache
  • Também é possível definir um array em cacheTag para aplicar e invalidar várias tags ao mesmo tempo
export async function CachedWrapper({ children }) {  
  "use cache";  
  const header = await fetchHeader();  
  return (  
    <div>  
      <h1>{header}</h1>  
      {children} {/* conteúdo dinâmico é mantido como está */}  
    </div>  
  );  
}  
export async function ProductPage({ id }) {  
  "use cache";  
  cacheTag(["products", `product-${id}`, "featured"]);  
  // é possível invalidar usando qualquer uma dessas tags  
}  

Hierarquia de cache

  • Ao declarar "use cache" no nível mais alto, toda aquela área passa a ser armazenada em cache
  • Partes específicas (por exemplo, seções dinâmicas com Suspense) podem ficar fora da área de cache
"use cache";  
export default async function Page() {  
  return (  
    <div>  
      <CachedHeader />  
      <div>  
        <Suspense fallback={<Loading />}>  
          <DynamicFeed /> {/* conteúdo dinâmico */}  
        </Suspense>  
      </div>  
    </div>  
  );  
}  

Segurança de tipos

  • Strings como chaves de cache e perfis de cache podem ser gerenciadas como constantes para reduzir o uso de magic strings
  • É prático usar uma abordagem que gere tags, no estilo dos padrões do React Query
// gerenciar chaves de perfil de cache como constantes  
export const CACHE_LIFE_KEYS = {  
  blog: "blog",  
} as const;  
  
const config = {  
  experimental: {  
    cacheLife: {  
      [CACHE_LIFE_KEYS.blog]: {  
        stale: 3600,  
        revalidate: 900,  
        expire: 86400,  
      },  
    },  
  },  
};  

Como gerenciar tags de cache com eficiência

  • Aplicar o padrão de factory de tags no estilo React Query
export const CACHE_TAGS = {  
  blog: {  
    all: ["blog"] as const,  
    list: () => [...CACHE_TAGS.blog.all, "list"] as const,  
    post: (id: string) => [...CACHE_TAGS.blog.all, "post", id] as const,  
    comments: (postId: string) =>  
      [...CACHE_TAGS.blog.all, "post", postId, "comments"] as const,  
  },  
} as const;  
  
// Definição de tags de cache  
function tagCache(tags: string[]) {  
  cacheTag(...tags);  
}  
  
// Exemplo de uso  
export async function BlogList() {  
  "use cache";  
  tagCache(CACHE_TAGS.blog.list());  
}  

3 comentários

 
schang124 2025-03-03

Parece melhor usar frameworks como Next.js ou Remix apenas quando o SEO é importante e há necessidade de SSR.

Acho que é preciso ter cautela ao adotar Next.js em serviços nos quais SEO não é importante, como produtos B2B ou back office. Isso porque a interface e a complexidade impostas pelo Next.js podem reduzir a produtividade no desenvolvimento.

Pessoalmente, acho que, quando SEO não é necessário, Vite + React é muito melhor em termos de produtividade de desenvolvimento e flexibilidade.

 
[Este comentário foi ocultado.]
 
9vvin 2025-02-25

O Next.js ficou bem utilizável desde a versão 13, mas ultimamente tenho gostado dele de verdade. Acho que vai se tornar o padrão de fato da stack tecnológica de desenvolvimento web full stack.