用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/autohandai/community-skills --skill nextjs-app-router-mastery命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| name | nextjs-app-router-mastery |
| description | Next.js 14+ App Router patterns, server components, and data fetching |
| license | MIT |
| compatibility | nextjs 14+, react 18+ |
| allowed-tools | read_file write_file apply_patch search_with_context run_command |
'use client'app/
layout.tsx # Root layout (required)
page.tsx # Route UI
loading.tsx # Loading UI (Suspense boundary)
error.tsx # Error boundary
not-found.tsx # 404 UI
route.ts # API route handler
template.tsx # Re-renders on navigation
default.tsx # Parallel route fallback
// app/posts/page.tsx - Server Component
async function PostsPage() {
const posts = await fetchPosts(); // Direct fetch, no useEffect
return <PostList posts={posts} />;
}
async function Dashboard() {
// Parallel fetches - don't await sequentially
const [user, posts, analytics] = await Promise.all([
fetchUser(),
fetchPosts(),
fetchAnalytics(),
]);
return <DashboardView user={user} posts={posts} analytics={analytics} />;
}
export default function Page() {
return (
<div>
<h1>Dashboard</h1>
<Suspense fallback={<StatsSkeleton />}>
<Stats /> {/* Async component */}
</Suspense>
<Suspense fallback={<ChartSkeleton />}>
<Chart /> {/* Streams in when ready */}
</Suspense>
</div>
);
}
// app/actions.ts
'use server';
import { revalidatePath } from 'next/cache';
export async function createPost(formData: FormData) {
const title = formData.get('title') as string;
await db.posts.create({ data: { title } });
revalidatePath('/posts');
}
// app/api/posts/route.ts
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
const posts = await fetchPosts();
return NextResponse.json(posts);
}
export async function POST(request: Request) {
const body = await request.json();
const post = await createPost(body);
return NextResponse.json(post, { status: 201 });
}
// Force dynamic rendering
export const dynamic = 'force-dynamic';
// Revalidate every 60 seconds
export const revalidate = 60;
// Static generation
export const dynamic = 'force-static';
// Per-fetch revalidation
fetch(url, { next: { revalidate: 3600 } });
// On-demand revalidation
revalidatePath('/posts');
revalidateTag('posts');
// Static metadata
export const metadata: Metadata = {
title: 'My App',
description: 'App description',
};
// Dynamic metadata
export async function generateMetadata({ params }): Promise<Metadata> {
const post = await fetchPost(params.id);
return { title: post.title };
}
loading.tsx for route-level loading states(group) for organization without affecting URL