14 Punkte von xguru 2025-02-24 | 3 Kommentare | Auf WhatsApp teilen
  • Die künftige Richtung von Next.js ist spannend
  • Es gab zwar Probleme mit Server Actions, aber mit useOptimistic und useFormStatus aus React 19 scheint eine Verbesserung möglich
    • Auch der useFetcher-Ansatz von Remix bietet eine gute DX
  • Besonders hervor stechen PPR (Partial Pre-rendering) von Next.js und das neue granulare Cache-System
  • Insgesamt hinterlässt es einen sehr positiven Eindruck

The Big Picture

  • Das neue Cache-System kann in next.config.js experimentell aktiviert werden
  • Cache-Profile lassen sich definieren, um unterschiedliche Ablaufzeiten und Revalidierungsintervalle festzulegen
// next.config.js  
const config = {  
  experimental: {  
    // Neues Caching-System aktivieren. Jetzt kann `use cache` im Code verwendet werden  
    dynamicIO: true,   
    // Optional: Cache-Profile konfigurieren  
    cacheLife: {  
      blog: {  
        stale: 3600, // Client-Cache beibehalten: 1 Stunde  
        revalidate: 900, // Auf dem Server aktualisieren: 15 Minuten  
        expire: 86400, // Maximale Lebensdauer: 1 Tag  
      },  
    },  
  },  
};  

Grundlegende Verwendung von use cache

  • Caching ist auf Datei-, Komponenten- und Funktionsebene über die Deklaration "use cache" möglich
  • Im Codebeispiel lässt sich Caching einfach anwenden, indem use cache hinzugefügt wird
  • Mit cacheTag, revalidateTag usw. kann der Cache zum gewünschten Zeitpunkt invalidiert werden
// 1. Caching auf Dateiebene  
"use cache";  
export default function Page() {  
  return <div>Cached Page</div>;  
}  
  
// 2. Caching auf Komponentenebene  
export async function PriceDisplay() {  
  "use cache";  
  const price = await fetchPrice();  
  return <div>${price}</div>;  
}  
  
// 3. Caching auf Funktionsebene  
export async function getData() {  
  "use cache";  
  return await db.query();  
}  

Tag-basiertes Caching

import { unstable_cacheTag as cacheTag, revalidateTag } from 'next/cache';  
  
// Bestimmte Datengruppe cachen  
export async function ProductList() {  
  'use cache';  
  cacheTag('products');  
  const products = await fetchProducts();  
  return <div>{products}</div>;  
}  
  
// Cache bei Datenänderungen invalidieren  
export async function addProduct() {  
  'use server';  
  await db.products.add(...);  
  revalidateTag('products');  
}  

Benutzerdefinierte Cache-Profile

  • Mit unstable_cacheLife können die in next.config.js definierten Cache-Profile geladen werden
  • Im Code wird der deklarierte Profilname (z. B. &quot;blog&quot;) verwendet, um die Cache-Richtlinie anzuwenden
import { unstable_cacheLife as cacheLife } from "next/cache";  
  
export async function BlogPosts() {  
  "use cache";  
  cacheLife("blog"); // Vordefiniertes Cache-Profil für den Blog verwenden  
  return await fetchPosts();  
}  

Wichtige, aber leicht zu übersehende Punkte

Automatische Generierung von Cache-Keys

  • props und arguments einer Komponente werden automatisch in den Cache-Key aufgenommen
  • Nicht serialisierbare Werte (z. B. Funktionen) werden als „unveränderliche Referenz“ behandelt
export async function UserCard({ id, onDelete }) {  
  "use cache";  
  // id wird in den Cache-Key aufgenommen  
  // onDelete wird übergeben, beeinflusst das Caching aber nicht  
  const user = await fetchUser(id);  
  return <div onClick={onDelete}>{user.name}</div>;  
}  

Mischung aus dynamischen und gecachten Inhalten

  • Dynamische Inhalte können als Child innerhalb gecachter Inhalte übergeben und gemischt verwendet werden
  • Durch Angabe eines cacheTag-Arrays können mehrere Tags gleichzeitig angewendet und invalidiert werden
export async function CachedWrapper({ children }) {  
  "use cache";  
  const header = await fetchHeader();  
  return (  
    <div>  
      <h1>{header}</h1>  
      {children} {/* Dynamische Inhalte bleiben unverändert */}  
    </div>  
  );  
}  
export async function ProductPage({ id }) {  
  "use cache";  
  cacheTag(["products", `product-${id}`, "featured"]);  
  // Die Invalidierung ist über jeden dieser Tags möglich  
}  

Caching-Hierarchie

  • Wenn &quot;use cache&quot; auf der obersten Ebene deklariert wird, wird der gesamte Bereich gecacht
  • Bestimmte Teile (z. B. dynamische Abschnitte mit Suspense) können aus dem Caching-Bereich ausgenommen werden
"use cache";  
export default async function Page() {  
  return (  
    <div>  
      <CachedHeader />  
      <div>  
        <Suspense fallback={<Loading />}>  
          <DynamicFeed /> {/* Dynamischer Inhalt */}  
        </Suspense>  
      </div>  
    </div>  
  );  
}  

Typsicherheit

  • Strings wie Cache-Keys und Cache-Profile können als Konstanten verwaltet werden, um Magic Strings zu reduzieren
  • Praktisch ist ein Muster zur Tag-Erzeugung, ähnlich wie bei React Query
// Cache-Profilschlüssel als Konstanten verwalten  
export const CACHE_LIFE_KEYS = {  
  blog: "blog",  
} as const;  
  
const config = {  
  experimental: {  
    cacheLife: {  
      [CACHE_LIFE_KEYS.blog]: {  
        stale: 3600,  
        revalidate: 900,  
        expire: 86400,  
      },  
    },  
  },  
};  

So verwaltet man Cache-Tags effizient

  • Anwendung eines Tag-Factory-Musters im Stil von 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;  
  
// Caching-Tags setzen  
function tagCache(tags: string[]) {  
  cacheTag(...tags);  
}  
  
// Verwendungsbeispiel  
export async function BlogList() {  
  "use cache";  
  tagCache(CACHE_TAGS.blog.list());  
}  

3 Kommentare

 
schang124 2025-03-03

Ich denke, es ist sinnvoll, ein Framework wie Next.js oder Remix nur dann zu verwenden, wenn SSR wegen der Bedeutung von SEO wirklich erforderlich ist.

Gerade bei B2B-Business-Produkten oder Services wie Backoffice-Anwendungen, bei denen SEO nicht wichtig ist, sollte man die Einführung von Next.js meiner Meinung nach sorgfältig abwägen. Denn die von Next.js vorgegebenen Interfaces und die zusätzliche Komplexität können die Entwicklungsproduktivität senken.

Persönlich finde ich, dass in Fällen, in denen SEO nicht notwendig ist, Vite + React in Bezug auf Entwicklungsproduktivität und Flexibilität deutlich besser ist.

 
[Dieser Kommentar wurde ausgeblendet.]
 
9vvin 2025-02-25

Next.js ist seit Version 13 wirklich brauchbar geworden, und in letzter Zeit gefällt es mir sogar richtig gut. Es scheint de facto zum Standard für den Full-Stack-Webentwicklungs-Stack zu werden.