Skip to main content

nextjs-data-fetching

Use when next.js data fetching patterns including SSG, SSR, and ISR. Use when building data-driven Next.js applications.

Quellinformationen

Repository
TheBushidoCollective/han
Letzte Quellaktivität
11. Februar 2026 um 17:47
Erkannte Sprache von SKILL.md
Englisch
Sterne
200
Forks
24

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
nextjs-data-fetching
user-invocable
false
description
Use when next.js data fetching patterns including SSG, SSR, and ISR. Use when building data-driven Next.js applications.
allowed-tools
["Bash","Read"]
# Next.js Data Fetching Master data fetching in Next.js with static generation, server-side rendering, and incremental static regeneration. ## Fetch with Caching Strategies ```typescript // Default: 'force-cache' (similar to SSG) export default async function Page() { const data = await fetch('https://api.example.com/data'); const json = await data.json(); return <div>{json.title}</div>; } // No caching: 'no-store' (similar to SSR) export default async function DynamicPage() { const data = await fetch('https://api.example.com/data', { cache: 'no-store' }); const json = await data.json(); return <div>{json.title}</div>; } // Revalidate every 60 seconds (ISR) export default async function RevalidatedPage() { const data = await fetch('https://api.example.com/data', { next: { revalidate: 60 } }); const json = await data.json(); return <div>{json.title}</div>; } // Per-route caching config export const revalidate = 3600; // Revalidate every hour export default async function Page() { const data = await fetch('https://api.example.com/data'); return <div>{data.title}</div>; } // Dynamic rendering export const dynamic = 'force-dynamic'; // Equivalent to cache: 'no-store' export const dynamic = 'force-static'; // Equivalent to cache: 'force-cache' export const dynamic = 'error'; // Error if dynamic functions used export const dynamic = 'auto'; // Default behavior ``` ## Static Generation with generateStaticParams ```typescript // app/posts/[id]/page.tsx interface Post { id: string; title: string; content: string; } // Generate static paths at build time export async function generateStaticParams() { const posts = await fetch('https://api.example.com/posts').then(r => r.json()); return posts.map((post: Post) => ({ id: post.id.toString() })); } export default async function Post({ params }: { params: { id: string } }) { const post = await fetch(`https://api.example.com/posts/${params.id}`, { next: { revalidate: 3600 } // Revalidate hourly }).then(r => r.json()); return ( <article> <h1>{post.title}</h1> <p>{post.content}</p> </article> ); } // Multiple dynamic segments // app/shop/[category]/[product]/page.tsx export async function generateStaticParams() { const categories = await getCategories(); const paths = await Promise.all( categories.map(async (category) => { const products = await getProducts(category.slug); return products.map((product) => ({ category: category.slug, product: product.slug })); }) ); return paths.flat(); } export default async function Product({ params }: { params: { category: string; product: string } }) { const product = await getProduct(params.category, params.product); return ( <div> <h1>{product.name}</h1> <p>{product.description}</p> </div> ); } // Limit static generation for large datasets export const dynamicParams = true; // Default: generate on-demand export const dynamicParams = false; // Return 404 for ungenerated paths export async function generateStaticParams() { // Only generate top 100 posts at build time const posts = await getPosts({ limit: 100 }); return posts.map((post) => ({ id: post.id })); } ``` ## Time-Based Revalidation (ISR) ```typescript // Page-level revalidation export const revalidate = 60; // Revalidate every 60 seconds export default async function Page() { const posts = await fetch('https://api.example.com/posts').then(r => r.json()); return ( <div> {posts.map(post => ( <article key={post.id}> <h2>{post.title}</h2> </article> ))} </div> ); } // Per-request revalidation export default async function Page() { const staticData = await fetch('https://api.example.com/static', { next: { revalidate: 3600 } // Cache for 1 hour }).then(r => r.json()); const dynamicData = await fetch('https://api.example.com/dynamic', { next: { revalidate: 10 } // Cache for 10 seconds }).then(r => r.json()); return ( <div> <div>Static: {staticData.value}</div> <div>Dynamic: {dynamicData.value}</div> </div> ); } // Mixed caching strategies export default async function Dashboard() { // Never cache (always fresh) const liveData = await fetch('https://api.example.com/live', { cache: 'no-store' }).then(r => r.json()); // Cache indefinitely (build-time only) const staticData = await fetch('https://api.example.com/static', { cache: 'force-cache' }).then(r => r.json()); // Revalidate periodically const periodicData = await fetch('https://api.example.com/periodic', { next: { revalidate: 300 } }).then(r => r.json()); return ( <div> <LiveStats data={liveData} /> <StaticContent data={staticData} /> <PeriodicUpdates data={periodicData} /> </div> ); } ``` ## On-Demand Revalidation ```typescript // app/api/revalidate/route.ts import { revalidatePath, revalidateTag } from 'next/cache'; import { NextRequest, NextResponse } from 'next/server'; export async function POST(request: NextRequest) { const secret = request.nextUrl.searchParams.get('secret'); // Verify secret token if (secret !== process.env.REVALIDATE_SECRET) { return NextResponse.json({ error: 'Invalid secret' }, { status: 401 }); } const path = request.nextUrl.searchParams.get('path'); if (path) { // Revalidate specific path revalidatePath(path); return NextResponse.json({ revalidated: true, path }); } return NextResponse.json({ error: 'Missing path' }, { status: 400 }); } // app/posts/[slug]/page.tsx - Using cache tags export default async function Post({ params }: { params: { slug: string } }) { const post = await fetch(`https://api.example.com/posts/${params.slug}`, { next: { tags: ['posts', `post-${params.slug}`] } }).then(r => r.json()); return <article>{post.content}</article>; } // app/api/revalidate-tag/route.ts export async function POST(request: NextRequest) { const tag = request.nextUrl.searchParams.get('tag'); if (tag) { revalidateTag(tag); return NextResponse.json({ revalidated: true, tag }); } return NextResponse.json({ error: 'Missing tag' }, { status: 400 }); } // Server Action for revalidation 'use server'; import { revalidatePath } from 'next/cache'; export async function updatePost(id: string, data: FormData) { await db.post.update({ where: { id }, data }); // Revalidate the post page revalidatePath(`/posts/${id}`); // Revalidate the posts list revalidatePath('/posts'); } ``` ## Parallel Data Fetching ```typescript // Fetch multiple resources in parallel export default async function Page() { const [posts, categories, tags] = await Promise.all([ fetch('https://api.example.com/posts').then(r => r.json()), fetch('https://api.example.com/categories').then(r => r.json()), fetch('https://api.example.com/tags').then(r => r.json()) ]); return ( <div> <PostList posts={posts} /> <CategoryList categories={categories} /> <TagCloud tags={tags} /> </div> ); } // Parallel fetching with different cache strategies export default async function Dashboard() { const [stats, recentActivity, settings] = await Promise.all([ fetch('https://api.example.com/stats', { next: { revalidate: 60 } }).then(r => r.json()), fetch('https://api.example.com/activity', { cache: 'no-store' }).then(r => r.json()), fetch('https://api.example.com/settings', { cache: 'force-cache' }).then(r => r.json()) ]); return ( <div> <Stats data={stats} /> <Activity data={recentActivity} /> <Settings data={settings} /> </div> ); } // Fetching with fallbacks export default async function Page() { const results = await Promise.allSettled([ fetch('https://api.example.com/required').then(r => r.json()), fetch('https://api.example.com/optional1').then(r => r.json()), fetch('https://api.example.com/optional2').then(r => r.json()) ]); const [required, optional1, optional2] = results; return ( <div> {required.status === 'fulfilled' && <Required data={required.value} />} {optional1.status === 'fulfilled' && <Optional1 data={optional1.value} />} {optional2.status === 'fulfilled' && <Optional2 data={optional2.value} />} </div> ); } ``` ## Streaming and Suspense ```typescript // app/posts/page.tsx import { Suspense } from 'react'; export default function PostsPage() { return ( <div> <h1>Blog Posts</h1> {/* Stream featured posts */} <Suspense fallback={<FeaturedSkeleton />}> <FeaturedPosts /> </Suspense> {/* Stream all posts */} <Suspense fallback={<PostsSkeleton />}> <AllPosts /> </Suspense> {/* Stream comments */} <Suspense fallback={<CommentsSkeleton />}> <RecentComments /> </Suspense> </div> ); } async function FeaturedPosts() { const posts = await fetch('https://api.example.com/posts/featured', { next: { revalidate: 300 } }).then(r => r.json()); return ( <div className="featured"> {posts.map(post => ( <PostCard key={post.id} post={post} /> ))} </div> ); } async function AllPosts() { const posts = await fetch('https://api.example.com/posts', { next: { revalidate: 60 } }).then(r => r.json()); return ( <div className="posts"> {posts.map(post => (
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen