1310 字
7 分钟
Nextjs入门

Next.js 入门#

本文总结了常见的 Next.js 概念与实践,包括项目创建、路由、layout、服务端/客户端组件、数据获取、错误/加载处理、元数据、Server Action 与中间件等。

创建项目#

使用官方脚手架创建一个 Next.js 项目:

Terminal window
npx create-next-app@latest

注意:Node 环境要求 v18.18 及以上。

路由(基于文件系统)#

Next.js 的路由基于文件系统,一个文件夹代表一个路由,因此通常不需要使用 react-router。

创建页面#

app 目录下创建对应的文件夹,然后在该文件夹中创建 page.tsx(或 page.jsx),并导出一个 React 组件。该页面组件会被插入到对应层级的 layout 组件中。

动态路由#

通过在文件夹名中使用中括号创建动态路由,例如:

-[id]
|_ work
|_ page.js

将会对应路由 /:id/work

路由跳转#

  • Link 组件:用于声明式导航。
  • useRouter:用于编程式导航,提供 pushreplacebackrefresh 等方法。

useRouter 示例#

'use client'
import { useRouter } from 'next/navigation';
export default function MyComponent() {
const router = useRouter();
return (
<button onClick={() => router.push('/about')}>Go to About</button>
);
}

路由组#

使用小括号包裹文件夹名,创建一个路由组用于分组但不作为路由层级,例如:

app/
dashboard/
(layout)/
personal/
page.jsx
analyse/
page.jsx

路由组用于模块划分和共享布局。

layout(布局)#

在任意 app 目录下定义 layout.tsx,导出一个组件作为该层级及以下共享的框架。layout 组件需要接收 children 参数,默认为服务端组件:

app/dashboard/layout.tsx
import SideNav from './nav-link'
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<div className="flex h-screen">
<div className="w-64">
<SideNav />
</div>
<div className="flex-1">{children}</div>
</div>
)
}

切换页面时,layout 不会重新加载(保留状态)。

服务端组件 与 客户端组件#

Next.js 将默认组件视为服务端组件。若要将组件设为客户端组件,需要在文件顶部添加 "use client"

服务端组件(Server Components)#

  • 在服务器上渲染(返回 HTML)。
  • 不能使用浏览器 API 或 React client hooks。
  • 可以直接访问数据库或其他服务器资源。

客户端组件(Client Components)#

  • 在浏览器端运行。
  • 支持交互与状态(可以使用 React hooks)。
  • 不能直接访问服务器资源(需通过 fetch/API 获取)。

推荐:服务端负责数据,客户端负责交互#

父组件可以是服务端组件,内部嵌套客户端组件进行交互。

数据获取方式#

建议在服务端组件中进行数据请求,这样对 SEO 更友好,并能使用 Next.js 的缓存与 revalidate。常见方式:

1) 在服务端组件中直接使用 await + fetch#

app/page.tsx
export default async function Page() {
const res = await fetch('https://api.example.com/users')
const users = await res.json()
return (
<ul>
{users.map((u: any) => (
<li key={u.id}>{u.name}</li>
))}
</ul>
)
}

2) 直接使用服务器资源#

服务端组件可直接与数据库或本地服务代码交互(在安全的环境下)。

3) Next.js 缓存机制 与 revalidate#

(此处可补充:fetch 的 cache、next revalidate 选项,以及 ISR 的使用示例)

4) generateStaticParams / generateMetadata#

用于静态生成时提供参数或动态构造页面元数据(后面示例中会展示)。

客户端组件的数据获取#

  • 使用 useEffect + fetch
  • 使用 SWR 等客户端数据库

流式渲染 与 loading#

loading.tsx 是约定文件,用于在路由数据尚未准备好时显示占位 UI。Next.js 会在异步组件外层自动使用 Suspense

<Suspense fallback={<Loading />}>
<Page />
</Suspense>

错误处理#

error.tsx 用于捕获渲染错误并显示回退 UI(此文件通常为客户端组件):

'use client'
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return (
<div className="flex flex-col items-center justify-center h-screen">
<h2 className="text-red-600 text-2xl font-bold">出错了 😢</h2>
<p className="mt-2 text-gray-600">{error.message}</p>
<button onClick={() => reset()} className="mt-4 px-4 py-2 bg-blue-600 text-white rounded">重试</button>
</div>
)
}

404 页面处理(not-found.tsx)#

not-found.tsx 用于处理 404 状态。示例:

export default function NotFound() {
return (
<div className="flex flex-col items-center justify-center h-screen">
<h2 className="text-3xl font-bold text-red-600">404 - 页面未找到 😢</h2>
<p className="mt-2 text-gray-600">请检查您访问的地址是否正确。</p>
</div>
)
}

服务端手动触发 404:

import { notFound } from 'next/navigation'
export default async function Page() {
const res = await fetch('https://api.example.com/user/123')
if (!res.ok) {
notFound() // 手动触发 404 页面
}
const data = await res.json()
return <div>{data.name}</div>
}

元数据(Metadata)#

通过在 layout.tsxpage.tsx 导出元数据对象或 generateMetadata 函数来设置页面的元信息,利于 SEO。

静态元数据#

export const metadata = {
title: "",
description: "",
keywords: [""],
}

动态 generateMetadata#

import { Metadata } from 'next'
export async function generateMetadata({ params }: { params: { id: string } }): Promise<Metadata> {
const post = await fetch(`https://api.example.com/posts/${params.id}`).then(res => res.json())
return {
title: post.title,
description: post.summary,
openGraph: {
title: post.title,
description: post.summary,
images: [post.coverImage],
},
}
}

服务端行为(Server Actions)#

Server Action 允许在服务器上运行函数并由客户端直接调用(不经过 HTTP API)。

'use server'
import { db } from '@/lib/db'
export async function createUser(data: { name: string; email: string }) {
const user = await db.user.create({ data })
return user
}

Server Action 可直接绑定表单并传递复杂数据结构,Next.js 会自动序列化。

中间件(middleware)#

中间件在请求到达页面或 API 之前执行,可用于重定向、认证、日志等。

import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl
const isLoggedIn = request.cookies.get('token')?.value
if (pathname.startsWith('/dashboard') && !isLoggedIn) {
return NextResponse.redirect(new URL('/login', request.url))
}
return NextResponse.next()
}
export const config = {
matcher: ['/dashboard/:path*', '/profile/:path*']
}
Nextjs入门
https://linrunxinnn.cn/posts/nextjs入门/
作者
linrunxinnn
发布于
2025-10-14
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时