14 puntos por xguru 2025-02-24 | 3 comentarios | Compartir por WhatsApp
  • La dirección futura de Next.js resulta interesante
  • Hubo algunos problemas con Server Actions, pero se ve potencial de mejora con useOptimistic y useFormStatus de React 19
    • El enfoque de useFetcher de Remix también ofrece una buena DX
  • El PPR (Partial Pre-rendering) de Next.js y el nuevo sistema de caché granular destacan especialmente
  • En general, deja una impresión muy positiva

The Big Picture

  • El nuevo sistema de caché se puede activar de forma experimental en next.config.js
  • Se pueden definir perfiles de caché para configurar distintos tiempos de expiración y ciclos de revalidación
// next.config.js  
const config = {  
  experimental: {  
    // Activa el nuevo sistema de caché. Ahora puedes usar `use cache` en el código  
    dynamicIO: true,   
    // Opcional: configuración de perfiles de caché  
    cacheLife: {  
      blog: {  
        stale: 3600, // Mantener caché del cliente: 1 hora  
        revalidate: 900, // Refrescar en el servidor: 15 minutos  
        expire: 86400, // Vida máxima: 1 día  
      },  
    },  
  },  
};  

Uso básico de use cache

  • Se puede habilitar caché a nivel de archivo, componente o función mediante la declaración "use cache"
  • En los ejemplos de código, basta con agregar use cache para aplicar caché fácilmente
  • Con cacheTag, revalidateTag, etc., se puede invalidar la caché en el momento deseado
// 1. Caché a nivel de archivo  
"use cache";  
export default function Page() {  
  return <div>Cached Page</div>;  
}  
  
// 2. Caché a nivel de componente  
export async function PriceDisplay() {  
  "use cache";  
  const price = await fetchPrice();  
  return <div>${price}</div>;  
}  
  
// 3. Caché a nivel de función  
export async function getData() {  
  "use cache";  
  return await db.query();  
}  

Caché basada en etiquetas

import { unstable_cacheTag as cacheTag, revalidateTag } from 'next/cache';  
  
// Guardar en caché un grupo específico de datos  
export async function ProductList() {  
  'use cache';  
  cacheTag('products');  
  const products = await fetchProducts();  
  return <div>{products}</div>;  
}  
  
// Invalidar la caché cuando cambien los datos  
export async function addProduct() {  
  'use server';  
  await db.products.add(...);  
  revalidateTag('products');  
}  

Perfil de Cache personalizado

  • Con unstable_cacheLife se pueden cargar los perfiles de caché definidos en next.config.js
  • La política de caché se aplica usando el nombre del perfil declarado dentro del código (por ejemplo, "blog")
import { unstable_cacheLife as cacheLife } from "next/cache";  
  
export async function BlogPosts() {  
  "use cache";  
  cacheLife("blog"); // Usa el perfil de caché predefinido para blog  
  return await fetchPosts();  
}  

Puntos importantes que pueden pasar desapercibidos

Generación automática de claves de caché

  • Los props y los arguments del componente se incluyen automáticamente en la clave de caché
  • Los valores no serializables (como funciones) se manejan como "referencias no modificables"
export async function UserCard({ id, onDelete }) {  
  "use cache";  
  // id se incluye en la clave de caché  
  // onDelete se pasa, pero no afecta el almacenamiento en caché  
  const user = await fetchUser(id);  
  return <div onClick={onDelete}>{user.name}</div>;  
}  

Mezcla de contenido dinámico y contenido en caché

  • Se puede combinar contenido en caché con contenido dinámico pasándolo como hijos dentro del contenido cacheado
  • Se puede especificar un arreglo de cacheTag para aplicar e invalidar varias etiquetas al mismo tiempo
export async function CachedWrapper({ children }) {  
  "use cache";  
  const header = await fetchHeader();  
  return (  
    <div>  
      <h1>{header}</h1>  
      {children} {/* El contenido dinámico se mantiene tal cual */}  
    </div>  
  );  
}  
export async function ProductPage({ id }) {  
  "use cache";  
  cacheTag(["products", `product-${id}`, "featured"]);  
  // Se puede invalidar usando cualquiera de estas etiquetas  
}  

Jerarquía de caché

  • Si se declara "use cache" en el nivel superior, toda esa área queda en caché
  • Algunas partes específicas (por ejemplo, secciones dinámicas con Suspense) pueden excluirse del área cacheada
"use cache";  
export default async function Page() {  
  return (  
    <div>  
      <CachedHeader />  
      <div>  
        <Suspense fallback={<Loading />}>  
          <DynamicFeed /> {/* Contenido dinámico */}  
        </Suspense>  
      </div>  
    </div>  
  );  
}  

Seguridad de tipos

  • Las cadenas como claves de caché y perfiles de caché se pueden manejar como constantes para reducir el uso de magic strings
  • Al usar un enfoque que genere etiquetas, como en el patrón de React Query, resulta más conveniente
// Gestionar claves de perfiles de caché 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,  
      },  
    },  
  },  
};  

Cómo gestionar eficientemente las etiquetas de caché

  • Aplicar el patrón de fábrica de etiquetas al 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;  
  
// Configurar etiquetas de caché  
function tagCache(tags: string[]) {  
  cacheTag(...tags);  
}  
  
// Ejemplo de uso  
export async function BlogList() {  
  "use cache";  
  tagCache(CACHE_TAGS.blog.list());  
}  

3 comentarios

 
schang124 2025-03-03

Parece que lo mejor es usar frameworks como Next.js o Remix solo cuando el SEO es importante y se necesita SSR.

Especialmente en servicios donde el SEO no es importante, como productos B2B o back office, creo que hay que pensar con cuidado antes de adoptar Next.js. Esto se debe a que las interfaces o la complejidad que impone Next.js pueden reducir la productividad de desarrollo.

Personalmente, creo que cuando el SEO no es necesario, Vite + React es mucho mejor en términos de productividad de desarrollo y flexibilidad.

 
[Este comentario fue ocultado.]
 
9vvin 2025-02-25

Next.js se volvió bastante usable desde la versión 13, pero últimamente de verdad me encanta muchísimo. Creo que se va a convertir en el estándar de facto del stack tecnológico para desarrollo web full-stack.