页面 metadata
export const metadata = {
title: "页面标题",
description: "页面描述",
};框架
App Router、导航、数据获取与常用配置片段。 — 共 19 条
共 19 条代码片段
export const metadata = {
title: "页面标题",
description: "页面描述",
};type Props = {
params: Promise<{ slug: string }>;
};
export async function generateMetadata({ params }: Props) {
const { slug } = await params;
return {
title: slug,
description: `关于 ${slug} 的页面`,
};
}type Props = {
params: Promise<{ slug: string }>;
};
export default async function Page({ params }: Props) {
const { slug } = await params;
return <div>{slug}</div>;
}type Props = {
searchParams: Promise<{ q?: string; page?: string }>;
};
export default async function Page({ searchParams }: Props) {
const { q = "", page = "1" } = await searchParams;
return (
<div>
关键词:{q} / 页码:{page}
</div>
);
}export function generateStaticParams() {
return [{ slug: "a" }, { slug: "b" }, { slug: "c" }];
}import { notFound } from "next/navigation";
export default async function Page({ params }: Props) {
const data = await getData((await params).id);
if (!data) notFound();
return <div>{data.title}</div>;
}import { redirect, permanentRedirect } from "next/navigation";
redirect("/login");
permanentRedirect("/new-path");// app/blog/loading.tsx
export default function Loading() {
return <div>加载中…</div>;
}// app/blog/error.tsx
"use client";
export default function Error({
error,
reset,
}: {
error: Error;
reset: () => void;
}) {
return (
<div>
<p>{error.message}</p>
<button onClick={reset}>重试</button>
</div>
);
}"use client";
import { useState } from "react";
export default function Counter() {
const [n, setN] = useState(0);
return <button onClick={() => setN(n + 1)}>{n}</button>;
}import Link from "next/link";
<Link href="/blog">博客</Link>
<Link href={`/blog/${slug}`}>{title}</Link>"use client";
import { useRouter } from "next/navigation";
const router = useRouter();
router.push("/dashboard");
router.replace("/login");
router.back();
router.refresh();"use client";
import { usePathname, useSearchParams } from "next/navigation";
const pathname = usePathname();
const searchParams = useSearchParams();
const q = searchParams.get("q");import Image from "next/image";
<Image
src="/cover.jpg"
alt="封面"
width={800}
height={450}
priority
/>const res = await fetch("https://api.example.com/posts", {
next: { revalidate: 60 }, // ISR
});
const data = await res.json();// 强制缓存
await fetch(url, { cache: "force-cache" });
// 不缓存
await fetch(url, { cache: "no-store" });// app/api/hello/route.ts
import { NextResponse } from "next/server";
export async function GET() {
return NextResponse.json({ ok: true });
}
export async function POST(request: Request) {
const body = await request.json();
return NextResponse.json({ received: body });
}import { revalidatePath, revalidateTag } from "next/cache";
revalidatePath("/blog");
revalidateTag("posts");import type { NextConfig } from "next";
const nextConfig: NextConfig = {
images: {
remotePatterns: [
{ protocol: "https", hostname: "cdn.example.com" },
],
},
async redirects() {
return [{ source: "/old", destination: "/new", permanent: true }];
},
};
export default nextConfig;# .env.local
NEXT_PUBLIC_API_HOST=https://api.example.com
API_SECRET=xxx
# 客户端可读:NEXT_PUBLIC_*
process.env.NEXT_PUBLIC_API_HOST
# 仅服务端
process.env.API_SECRET