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

7.4 KiB
Raw Permalink Blame History

next.js

Routing

创建路由

next.js使用基于文件系统的路由文件路径用于定于路由。
每一个文件夹都代表到一个匹配到URL segmentroute segment,为了创建嵌套路由,可以在文件夹中嵌套文件夹。

  • 例如app文件夹代表根URLapp/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的示例如下

// 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示例如下

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

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

export default function Template({ children }) {
  return <div>{children}</div>;
}

如果一个route segment同时具有template和layout那么渲染输出如下所示

<Layout>
  {/* Note that the template is given a unique key. */}
  <Template key={routeParam}>{children}</Template>
</Layout>

修改head

在app目录中可以自定义html文件的head标签的属性例如titlemeta
需要在page.js或layout.js中导出一个metadata的对象

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属性中写入目标路径

import Link from 'next/link';
 
export default function Page() {
  return <Link href="/dashboard">Dashboard</Link>;
}

路由到动态的路径

如果想要路由到动态的路径,可以按照如下方式:

// 在路径字符串中,可以通过${}来动态获取值
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}

<Link href="/#hashid" scroll={false}>
  Scroll to specific id.
</Link>

useRouter

useRouter允许client component在代码中触发路由的跳转如果要使用useRouter需要导入next/navigation中的useRouter

'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中被忽略

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参数传入动态路由使用如下所示

// 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>;
}