Skip to main content Skills Marketplace Descubra e explore skills de IA criadas pela comunidade.
Ocupações relacionadas SOC
Baseado na classificação ocupacional SOC
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Copiar promptMostrar detalhes do prompt Um comando direto ignora o prompt de revisão. Verifique a origem antes de executá-lo.
npx skills add https://github.com/TheBushidoCollective/han --skill nextjs-data-fetchingO comando permanece em uma só linha. Role horizontalmente para revisá-lo antes de copiar.
Prefere uma cópia local? Baixe os arquivos disponíveis atualmente no SkillsMP.
Baixar Zip Baixando... 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
export default async function Page ( ) {
const data = await fetch ('https://api.example.com/data' );
const json = await data.json ();
return <div > {json.title}</div > ;
}
( ) {
data = ( , {
:
});
json = data. ();
;
}
( ) {
data = ( , {
: { : }
});
json = data. ();
;
}
revalidate = ;
( ) {
data = ( );
;
}
dynamic = ;
dynamic = ;
dynamic = ;
dynamic = ;
export
default
async
function
DynamicPage
const
await
fetch
'https://api.example.com/data'
cache
'no-store'
const
await
json
return
<div > {json.title}</div >
export
default
async
function
RevalidatedPage
const
await
fetch
'https://api.example.com/data'
next
revalidate
60
const
await
json
return
<div > {json.title}</div >
export
const
3600
export
default
async
function
Page
const
await
fetch
'https://api.example.com/data'
return
<div > {data.title}</div >
export
const
'force-dynamic'
export
const
'force-static'
export
const
'error'
export
const
'auto'
Static Generation with generateStaticParams
interface Post {
id : string ;
title : string ;
content : string ;
}
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 }
}).then (r => r.json ());
return (
<article >
<h1 > {post.title}</h1 >
<p > {post.content}</p >
</article >
);
}
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 >
);
}
export const dynamicParams = true ;
export const dynamicParams = false ;
export async function generateStaticParams ( ) {
const posts = await getPosts ({ limit : 100 });
return posts.map ((post ) => ({
id : post.id
}));
}
Time-Based Revalidation (ISR)
export const revalidate = 60 ;
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 >
);
}
export default async function Page ( ) {
const staticData = await fetch ('https://api.example.com/static' , {
next : { revalidate : 3600 }
}).then (r => r.json ());
const dynamicData = await fetch ('https://api.example.com/dynamic' , {
next : { revalidate : 10 }
}).then (r => r.json ());
return (
<div >
<div > Static: {staticData.value}</div >
<div > Dynamic: {dynamicData.value}</div >
</div >
);
}
export default async function Dashboard ( ) {
const liveData = await fetch ('https://api.example.com/live' , {
cache : 'no-store'
}).then (r => r.json ());
const staticData = await fetch ('https://api.example.com/static' , {
cache : 'force-cache'
}).then (r => r.json ());
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
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' );
if (secret !== process.env .REVALIDATE_SECRET ) {
return NextResponse .json ({ error : 'Invalid secret' }, { status : 401 });
}
const path = request.nextUrl .searchParams .get ('path' );
if (path) {
revalidatePath (path);
return NextResponse .json ({ revalidated : true , path });
}
return NextResponse .json ({ error : 'Missing path' }, { status : 400 });
}
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 > ;
}
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 });
}
'use server' ;
import { revalidatePath } from 'next/cache' ;
export async function updatePost (id : string , data : FormData ) {
await db.post .update ({ where : { id }, data });
revalidatePath (`/posts/${id} ` );
revalidatePath ('/posts' );
}
Parallel Data Fetching
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 >
);
}
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 >
);
}
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
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 => (
<PostCard key ={post.id} post ={post} />
))}
</div >
);
}
async function RecentComments ( ) {
const comments = await fetch ('https://api.example.com/comments/recent' , {
cache : 'no-store'
}).then (r => r.json ());
return (
<div className ="comments" >
{comments.map(comment => (
<Comment key ={comment.id} comment ={comment} />
))}
</div >
);
}
Loading States
export default function Loading ( ) {
return (
<div className ="loading" >
<div className ="skeleton skeleton-title" />
<div className ="skeleton skeleton-text" />
<div className ="skeleton skeleton-text" />
<div className ="skeleton skeleton-text" />
</div >
);
}
export default function Page ( ) {
return (
<div >
<Suspense fallback ={ <CustomLoading message ="Loading posts..." /> }>
<Posts />
</Suspense >
<Suspense fallback ={ <CustomLoading message ="Loading comments..." /> }>
<Comments />
</Suspense >
</div >
);
}
function CustomLoading ({ message }: { message: string } ) {
return (
<div className ="custom-loading" >
<Spinner />
<p > {message}</p >
</div >
);
}
export default function Page ( ) {
return (
<div >
{/* Shows immediately */}
<InstantHeader />
{/* Streams in as ready */}
<Suspense fallback ={ <FastSkeleton /> }>
<FastContent />
</Suspense >
<Suspense fallback ={ <SlowSkeleton /> }>
<SlowContent />
</Suspense >
</div >
);
}
Error Handling
'use client' ;
export default function Error ({
error,
reset
}: {
error: Error & { digest?: string };
reset: () => void ;
} ) {
return (
<div className ="error" >
<h2 > Failed to load posts</h2 >
<p > {error.message}</p >
<button onClick ={reset} > Try again</button >
</div >
);
}
export default async function Page ( ) {
try {
const data = await fetch ('https://api.example.com/data' , {
next : { revalidate : 60 }
});
if (!data.ok ) {
throw new Error (`Failed to fetch: ${data.status} ` );
}
const json = await data.json ();
return <Content data ={json} /> ;
} catch (error) {
console .error ('Fetch error:' , error);
return <ErrorFallback /> ;
}
}
export default async function Page ( ) {
let data;
try {
const res = await fetch ('https://api.example.com/data' );
data = await res.json ();
} catch (error) {
console .error ('Failed to fetch data:' , error);
data = null ;
}
return (
<div >
{data ? (
<Content data ={data} />
) : (
<div >
<p > Unable to load content</p >
<StaticFallback />
</div >
)}
</div >
);
}
'use client' ;
import { useState } from 'react' ;
export default function ErrorWithRetry ({
error,
reset
}: {
error: Error ;
reset: () => void ;
} ) {
const [retrying, setRetrying] = useState (false );
const handleRetry = async ( ) => {
setRetrying (true );
await new Promise (resolve => setTimeout (resolve, 1000 ));
reset ();
setRetrying (false );
};
return (
<div >
<h2 > Something went wrong</h2 >
<p > {error.message}</p >
<button onClick ={handleRetry} disabled ={retrying} >
{retrying ? 'Retrying...' : 'Retry'}
</button >
</div >
);
}
Server Actions for Mutations
'use server' ;
import { revalidatePath } from 'next/cache' ;
export async function createPost (formData : FormData ) {
const title = formData.get ('title' ) as string ;
const content = formData.get ('content' ) as string ;
try {
const res = await fetch ('https://api.example.com/posts' , {
method : 'POST' ,
headers : { 'Content-Type' : 'application/json' },
body : JSON .stringify ({ title, content })
});
if (!res.ok ) {
throw new Error ('Failed to create post' );
}
const post = await res.json ();
revalidatePath ('/posts' );
return { success : true , post };
} catch (error) {
return { success : false , error : error.message };
}
}
export async function updatePost (id : string , formData : FormData ) {
const title = formData.get ('title' ) as string ;
const content = formData.get ('content' ) as string ;
await fetch (`https://api.example.com/posts/${id} ` , {
method : 'PUT' ,
headers : { 'Content-Type' : 'application/json' },
body : JSON .stringify ({ title, content })
});
revalidatePath (`/posts/${id} ` );
revalidatePath ('/posts' );
}
export async function deletePost (id : string ) {
await fetch (`https://api.example.com/posts/${id} ` , {
method : 'DELETE'
});
revalidatePath ('/posts' );
}
import { createPost } from '../actions' ;
export default function NewPost ( ) {
return (
<form action ={createPost} >
<input name ="title" placeholder ="Title" required />
<textarea name ="content" placeholder ="Content" required />
<button type ="submit" > Create Post</button >
</form >
);
}
'use client' ;
import { useFormState, useFormStatus } from 'react-dom' ;
import { createPost } from './actions' ;
function SubmitButton ( ) {
const { pending } = useFormStatus ();
return (
<button type ="submit" disabled ={pending} >
{pending ? 'Creating...' : 'Create Post'}
</button >
);
}
export default function CreatePostForm ( ) {
const [state, formAction] = useFormState (createPost, null );
return (
<form action ={formAction} >
<input name ="title" required />
<textarea name ="content" required />
{state?.error && <p className ="error" > {state.error}</p > }
{state?.success && <p className ="success" > Post created!</p > }
<SubmitButton />
</form >
);
}
Request Memoization
async function getUser (id : string ) {
const res = await fetch (`https://api.example.com/users/${id} ` );
return res.json ();
}
export default async function Page ( ) {
const user1 = await getUser ('1' );
const user2 = await getUser ('1' );
const user3 = await getUser ('1' );
return <div > {user1.name}</div > ;
}
async function UserHeader ( ) {
const user = await getUser ('1' );
return <header > {user.name}</header > ;
}
async function UserProfile ( ) {
const user = await getUser ('1' );
return <div > {user.bio}</div > ;
}
export default function Page ( ) {
return (
<div >
<UserHeader />
<UserProfile />
</div >
);
}
import { cache } from 'react' ;
const getUser = cache (async (id : string ) => {
const res = await fetch (`https://api.example.com/users/${id} ` );
return res.json ();
});
Database Queries
import { db } from '@/lib/db' ;
export default async function Posts ( ) {
const posts = await db.post .findMany ({
where : { published : true },
orderBy : { createdAt : 'desc' },
take : 10
});
return (
<div >
{posts.map(post => (
<article key ={post.id} >
<h2 > {post.title}</h2 >
<p > {post.content}</p >
</article >
))}
</div >
);
}
export default async function Post ({ params }: { params: { id: string } } ) {
const post = await db.post .findUnique ({
where : { id : params.id },
include : {
author : true ,
comments : {
include : {
user : true
},
orderBy : { createdAt : 'desc' }
}
}
});
if (!post) {
notFound ();
}
return (
<article >
<h1 > {post.title}</h1 >
<p > By {post.author.name}</p >
<div > {post.content}</div >
<Comments comments ={post.comments} />
</article >
);
}
export default async function Dashboard ( ) {
const [totalPosts, totalUsers, recentActivity] = await Promise .all ([
db.post .count (),
db.user .count (),
db.activity .findMany ({
take : 10 ,
orderBy : { createdAt : 'desc' }
})
]);
return (
<div >
<StatsCard title ="Total Posts" value ={totalPosts} />
<StatsCard title ="Total Users" value ={totalUsers} />
<ActivityFeed items ={recentActivity} />
</div >
);
}
Pagination Patterns
export default async function Posts ({
searchParams
}: {
searchParams: { cursor?: string }
} ) {
const cursor = searchParams.cursor ;
const posts = await db.post .findMany ({
take : 10 ,
skip : cursor ? 1 : 0 ,
cursor : cursor ? { id : cursor } : undefined ,
orderBy : { createdAt : 'desc' }
});
const lastPost = posts[posts.length - 1 ];
const nextCursor = lastPost?.id ;
return (
<div >
<PostList posts ={posts} />
{nextCursor && (
<Link href ={ `/posts ?cursor =${nextCursor} `}> Load More</Link >
)}
</div >
);
}
export default async function Posts ({
searchParams
}: {
searchParams: { page?: string }
} ) {
const page = parseInt (searchParams.page || '1' );
const perPage = 10 ;
const [posts, total] = await Promise .all ([
db.post .findMany ({
skip : (page - 1 ) * perPage,
take : perPage,
orderBy : { createdAt : 'desc' }
}),
db.post .count ()
]);
const totalPages = Math .ceil (total / perPage);
return (
<div >
<PostList posts ={posts} />
<Pagination currentPage ={page} totalPages ={totalPages} />
</div >
);
}
'use client' ;
import { useState } from 'react' ;
import { loadMorePosts } from './actions' ;
export function InfinitePostList ({ initialPosts }: { initialPosts: Post[] } ) {
const [posts, setPosts] = useState (initialPosts);
const [loading, setLoading] = useState (false );
const loadMore = async ( ) => {
setLoading (true );
const lastId = posts[posts.length - 1 ].id ;
const newPosts = await loadMorePosts (lastId);
setPosts ([...posts, ...newPosts]);
setLoading (false );
};
return (
<div >
{posts.map(post => (
<PostCard key ={post.id} post ={post} />
))}
<button onClick ={loadMore} disabled ={loading} >
{loading ? 'Loading...' : 'Load More'}
</button >
</div >
);
}
When to Use This Skill Use nextjs-data-fetching when you need to:
Build static sites with dynamic data
Implement SSR for dynamic content
Use ISR for best of both worlds
Optimize for SEO and performance
Cache and revalidate data
Build e-commerce sites
Create content-heavy applications
Implement real-time updates
Build scalable applications
Handle large datasets efficiently
Implement pagination and infinite scroll
Optimize Core Web Vitals
Best Practices
Use static generation by default - Leverage SSG for pages that can be
pre-rendered at build time for optimal performance.
Implement ISR for frequently updated content - Use time-based or on-demand
revalidation for dynamic content that doesn't need real-time updates.
Cache API responses appropriately - Set proper revalidate times based on
how frequently data changes.
Use TypeScript for data types - Define proper types for API responses and
database queries to catch errors early.
Handle loading and error states - Implement loading.tsx and error.tsx files
for better user experience.
Implement proper revalidation strategies - Use on-demand revalidation with
webhooks for immediate updates when data changes.
Optimize for Core Web Vitals - Use streaming and Suspense to improve
perceived performance and loading times.
Use parallel data fetching - Fetch independent data sources simultaneously
to reduce waterfall effects.
Test data fetching patterns - Verify caching behavior, revalidation, and
error handling in tests.
Monitor performance metrics - Track cache hit rates, revalidation
frequency, and page load times.
Common Pitfalls
Not caching data appropriately - Using cache: 'no-store' for everything
defeats the performance benefits of SSG/ISR.
Overusing SSR for static content - Rendering static content on every
request wastes server resources.
Not implementing error boundaries - Missing error.tsx files cause poor
user experience when data fetching fails.
Ignoring revalidation strategies - Not setting revalidate times leads to
stale data or too many unnecessary requests.
Not handling race conditions - Parallel requests without proper ordering
can cause inconsistent UI state.
Missing loading states - Not implementing loading.tsx or Suspense boundaries
creates jarring loading experiences.
Not optimizing bundle size - Fetching too much data or including unnecessary
fields increases payload size.
Exposing sensitive API keys - Accidentally exposing secrets in client
components or client-side fetches.
Not testing edge cases - Skipping tests for error states, empty data, and
loading states leads to poor UX.
Misunderstanding caching behavior - Not knowing when Next.js caches requests
can lead to stale data or performance issues.
Resources