# 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

Hello, Next.js!

; } // `app/dashboard/page.tsx` is the UI for the `/dashboard` URL export default function Page() { return

Hello, Dashboard Page!

; } ``` 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 (
{/* Include shared UI here e.g. a header or sidebar */} {children}
); } ``` #### Root Layout(必须) root layout在app目录下被定义,并且应用于所有的route。该layout允许修改从server返回的初始html: ```js export default function RootLayout({ children }) { return ( {children} ); } ``` root layout使用需要满足如下条件 - app目录下必须包含一个root layout - root layout必须要定义``标签和``标签,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
{children}
; } ``` 如果一个route segment同时具有template和layout,那么渲染输出如下所示: ```js {/* Note that the template is given a unique key. */} ``` #### 修改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组件 ``是一个html组件,该组件继承了html``元素,用于提供routes之间的预取和导航。该组件是react组件之间进行跳转的主要方法。 如果要使用Link组件,需要从`next/link`中导入该组件,并且在组件的href属性中写入目标路径: ```js import Link from 'next/link'; export default function Page() { return Dashboard; } ``` #### 路由到动态的路径 如果想要路由到动态的路径,可以按照如下方式: ```js // 在路径字符串中,可以通过${}来动态获取值 import Link from 'next/link'; export default function PostList({ posts }) { return ( ); } ``` #### 跳转到目标的element 默认情况下,Link会跳转到目标route页面的顶部,如果想要跳转到目标route的指定位置,可以在href中加入`#${id}`。 ```js Scroll to specific id. ``` #### useRouter useRouter允许client component在代码中触发路由的跳转,如果要使用useRouter,需要导入`next/navigation`中的`useRouter`: ```js 'use client'; import { useRouter } from 'next/navigation'; export default function Page() { const router = useRouter(); return ( ); } ``` ### 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
My Post
; }