Files
rikako-note/react/next.js.md
2023-06-02 21:14:39 +08:00

197 lines
7.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# next.js
## Routing
### 创建路由
next.js使用基于文件系统的路由文件路径用于定于路由。
每一个文件夹都代表到一个匹配到`URL segment``route segment`,为了创建嵌套路由,可以在文件夹中嵌套文件夹。
- 例如app文件夹代表根URL`app/dashboard/settings`则是代表`/dashboard/settings`
- 而一个page.js文件则是让该route segment可以公共访问。
> 如果app/dashboard/路径下存在文件page.js则是代表该路径/dashboard可以被公共访问而另一个路径app/analytics下没有page.js文件则是代表该路径/analytics不能够被公共访问故而该路径可以被用于存储组件、样式表、图片和其他文件
### 创建UI
在位每一个route segment创建UI时会使用特殊的文件规范其中page会用于创建route UI而layout则是被用于创建被多个route所共享的UI。
### pages和layouts
#### pages
page UI每个都唯一对应一个route。可以通过在page.js文件中导出组件来定义page UI定义page.js可以让该路径变得公共可访问。
创建page的示例如下
```tsx
// app/page.tsx
export default function Page() {
return <h1>Hello, Next.js!</h1>;
}
// `app/dashboard/page.tsx` is the UI for the `/dashboard` URL
export default function Page() {
return <h1>Hello, Dashboard Page!</h1>;
}
```
pages使用须知
- root layout被应用下所有page共享
- 任意root segment可以选择定义自己的layout该layout会被在该segment下的所有page共享
- route中的layout默认是嵌套的每个parent layout都会使用child prop来包含嵌套layout
#### layouts
layout UI在多个page UI之间被共享。在导航时layout会保留state保持交互并且不会被重新渲染。layout也可以嵌套。
可以通过在layout.js中导出一个默认react组件来定义一个layout该组件应该接受一个children prop并且在渲染时被注入一个child layout或child page。
创建layout示例如下
```js
export default function DashboardLayout({
children, // will be a page or nested layout
}) {
return (
<section>
{/* Include shared UI here e.g. a header or sidebar */}
<nav></nav>
{children}
</section>
);
}
```
#### Root Layout(必须)
root layout在app目录下被定义并且应用于所有的route。该layout允许修改从server返回的初始html
```js
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
```
root layout使用需要满足如下条件
- app目录下必须包含一个root layout
- root layout必须要定义`<html>`标签和`<body>`标签next.js并不会自动创建它们
- 如果layout.js存在多层嵌套例如`/layout.js``/about/layout.js`,`/about/asahi/layout.js`都存在那么嵌套结构将是layout.js->about/layout.js->about/asahi/layout.js->about/asahi/page.js其中about/asahi/page.js渲染的效果将会包含上层所有的layout
#### template
template和layout相似在template中也可以包含子page和子layout。
layout和template区别如下
- layout在route跳转时layout本身维护的state会保持不变
- 而template在route跳转时**对于其每一个children都会含有一个独立的template实例**template在多个route进行跳转时state不会持久化
> 故而只有在layout中维护的state才会保持不变而template中维护的state在route之间进行跳转时会清空
可以通过创建一个template.js文件并且在文件中export default一个组件来定义template
```js
export default function Template({ children }) {
return <div>{children}</div>;
}
```
如果一个route segment同时具有template和layout那么渲染输出如下所示
```js
<Layout>
{/* Note that the template is given a unique key. */}
<Template key={routeParam}>{children}</Template>
</Layout>
```
#### 修改head
在app目录中可以自定义html文件的head标签的属性例如`title``meta`
需要在page.js或layout.js中导出一个metadata的对象
```js
export const metadata = {
title: 'Next.js',
};
export default function Page() {
return '...';
}
```
### linking and navigating
#### Link组件
`<Link>`是一个html组件该组件继承了html`<a>`元素用于提供routes之间的预取和导航。该组件是react组件之间进行跳转的主要方法。
如果要使用Link组件需要从`next/link`中导入该组件并且在组件的href属性中写入目标路径
```js
import Link from 'next/link';
export default function Page() {
return <Link href="/dashboard">Dashboard</Link>;
}
```
#### 路由到动态的路径
如果想要路由到动态的路径,可以按照如下方式:
```js
// 在路径字符串中,可以通过${}来动态获取值
import Link from 'next/link';
export default function PostList({ posts }) {
return (
<ul>
{posts.map((post) => (
<li key={post.id}>
<Link href={`/blog/${post.slug}`}>{post.title}</Link>
</li>
))}
</ul>
);
}
```
#### 跳转到目标的element
默认情况下Link会跳转到目标route页面的顶部如果想要跳转到目标route的指定位置可以在href中加入`#${id}`
```js
<Link href="/#hashid" scroll={false}>
Scroll to specific id.
</Link>
```
#### useRouter
useRouter允许client component在代码中触发路由的跳转如果要使用useRouter需要导入`next/navigation`中的`useRouter`
```js
'use client';
import { useRouter } from 'next/navigation';
export default function Page() {
const router = useRouter();
return (
<button type="button" onClick={() => router.push('/dashboard')}>
Dashboard
</button>
);
}
```
### route group
在app文件夹中通过通过文件路径结构来表示url path如果想要一个文件夹不影响url path可以将其标识为route group。
如果要创建route group可以用小括号将目录名包起来形式如下`
(foldername)`
#### 在不影响url path的情况下组织目录结构
为了在不影响url path的情况下组织目录结构可以通过如下方式来使用route group其中route group文件夹将会在url path中被忽略
```bash
app/(market)/about # 该url对应为/about
app/(shop)/account # 该url对应为/account
```
> 即使在使用route group时(market)和(shop)文件夹下共享同一路径'/',但是可以在(market)目录和(shop)目录下创建不同的layout.js文件
可以通过在(market)和(shop)下创建不同的layout.js位于(market)下的组件共享makretLayout位于(shop)下的组件共享shopLayout。
同理可以通过route group创建多个root layout。
### 动态路由
当不知道确切的segment name并且想要根据动态数据来创建route segment可以使用动态路由。
可以通过将文件夹名称通过`[]`包围起来来创建动态路由,例如`app/blog/[slug]/page.js`
动态数据将会被作为params参数传入动态路由使用如下所示
```js
// app/blog/[slug]/page.js
// params:{ slug: 'a' } url:/blog/a
// params:{ slug: 'b' } url:/blog/b
export default function Page({ params }) {
return <div>My Post</div>;
}