文件系统
App Router VS Page Router
nextjs 13起,使用新的路由模式——App Router
-
区别:
- Page Router 有缺陷,pages 目录下的文件会被当做路由文件,导致不能很好的组织代码。
- App Router 约定了特殊文件,在目录中使用特殊的字符可以更好的组织代码;
-
可以共存,但是App Router的优先级更高。
App router
- Routes
- Pages
- Layouts
- Templates
- Loading UI
- Error Handling
- 404
定义路由
用文件夹来定义路由 app/home , 对应的路由地址就是 /home
;以下定义了路由 /home
// app/home/page.tsx
export default function Page() {
return (
<h1> hello world </h1>
)
}
定义页面
在文件夹下创建 page.tsx;
// app/home/page.tsx
export default function Page() {
return (
<h1> hello world </h1>
)
}
如果是路由是 /about,则在 app 目录下新建 about文件夹,about 下,新建page.tsx文件即可
定义布局
-
在文件夹下创建
layout.tsx; -
app目录下的layout.tsx叫做根布局,必须包含html和body,且这个文件必须存在; -
根布局是服务端组件,且不可设置为客户端组件;
-
可以嵌套布局文件,比如在
app/menu/layout.tsx下,那menu下的所有页面都会共享该目录下的布局文件; -
布局文件会保持状态不被刷新,与
template.tsx不同;
import { Inter } from 'next/font/google'
import './globals.css'
import Link from 'next/link'
const inter = Inter({ subsets: ['latin'] })
// app/layout.tsx
export default function RootLayout({
children
}: Readonly<{
children: React.ReactNode
}>) {
return (
<html lang="en">
<body className={inter.className}>
<div>
<Link href="/about">About</Link>
<Link href="/settings">Setting</Link>
</div>
{children}
</body>
</html>
)
}
定义模板
-
在文件夹下创建
template.tsx; -
写法都跟
layout.tsx一样,但是template.tsx不会维持状态;
'use client'
// app/template.tsx
import { ReactNode, useEffect, useState } from 'react'
export default function Template({ children }: { children: ReactNode }) {
const [count, setCount] = useState<number>(0)
return (
<div>
<div>template: {count}</div>
<button
onClick={() => {
setCount(count + 1)
}}
>
Increment
</button>
<div>{children}</div>
</div>
)
}
-
所以选择
layout还是template,要看使用场景,比如依赖useEffect,useState,要保持表单状态,情况下使用template更合适
定义加载界面
-
在文件夹下创建
loading.tsx; -
实现原理其实是使用了react的
Suspense, ProfilePage 会 throw 一个数据加载的 promise,Suspense 会捕获这个 promise,追加一个 then 函数,then 函数中实现替换 fallback UI 。当数据加载完毕,promise 进入 resolve 状态,then 函数执行,于是更新替换 fallback UI;
// app/loading.tsx
export default function Loading() {
return <>Loading ...</>
}
// app/page.tsx
async function getData() {
await new Promise((resolve) => setTimeout(resolve, 3000))
return {
message: 'Hello, Dashboard!',
}
}
export default async function DashboardPage(props) {
const { message } = await getData()
return <h1>{message}</h1>
}}
定义错误处理
在文件夹下创建 error.tsx
定义404页面
在文件夹下创建 404.tsx