#05 No-code 之旅 — Next.js 的 Pages 与 Routing

嗨嗨嗨!昨天看完怎麽抓取资料的方式会影响到网页的渲染模式之後,今天的主题是 Next.js 的 Pages 与 Routing。Next.js 的 routing 方式跟一般 React 使用的 react-router 不一样,它采用 file-based routing

Next.js Pages & Routing

File-based Routing

File-based routing 的意思是每个档案代表一个 route,而档案名称 (file name) 会变成 route 的 path name (路径名称)。Next.js 会把 pages 资料夹 / 目录里面的所有档案看成 route (路径) 的一部分,还不是很懂吗?我们看看下面的例子~

  • pages/index.js 代表 / route
  • pages/about.js 代表 /about route

Index routes

每个 index 档案代表根目录,所以

  • pages/index.js 代表 / route
  • pages/posts/index.js 代表 /posts route

Nested (巢状) routes

每一层资料夹每一层目录会是 route 的一部分,所以

  • pages/posts/index.js 代表 /posts route
  • pages/posts/first.js 代表 /posts/first route
  • pages/categories/lifestyle/fashion.js 代表 /categories/lifestyle/fashion route

Dynamic (动态) routes

如果上面的 routes 都要我们自己定义每一个 file name 当 path name,那当我们有一系列的页面怎麽办?或是如果我们想要把资料库里的每一条资料写个页面怎麽办?或是像iT邦帮忙的网址 https://ithelp.ithome.com.tw/users/20141378 应该不会是我们要新增 20141378 个页面档案吧?这时候我们需要 dynamic routes 来帮助我们!

  • pages/posts/[pid]/index.js 代表 /posts/1/posts/2,···
  • pages/posts/[pid]/comments/index.js 代表 /posts/1/comments/posts/2/comments,···
  • pages/posts/[pid]/comments/[cid].js 代表 /posts/1/comments/1-1/posts/2/comments/2-1,···

或是iT邦帮忙的网址 https://ithelp.ithome.com.tw/users/20141378 需要一个档案 pages/users/[uid].js。这些动态的资讯可以在 route.query 物件里面看到,/posts/a/comments/a-1?utm_source=ithomequery 物件会长这样:

{ "pid": "a", "cid": "a-1", "utm_source": "ithome" }

Catch all routes

属於 dynamic routes 的一种,不过 catch all 的意思是不需要一个一个定义动态的部分,把所有动态的资讯抓起来,让 route 比较弹性,写法跟其余参数(rest parameter)一样。

  • pages/posts/[...slug].js 可以代表 /posts/a 也可以是 /posts/a/b/posts/a/b/c

slug 可以是 param 或是其他东西都可以,这些动态资讯也会出现在 query 物件里面,例如 /posts/a/b/cquery 会是:

{ "slug": ["a", "b", "c"] }

Optional catch all routes

知道了 catch all routes 之後,还有另一种更有弹性的 dynamic routes,只要把 catch all 的 [...slug] 改成 [[...slug]] 就会变成 optional catch all。意思是 slug 这个 array (阵列) 可以是不存在的,

  • pages/posts/[[...slug]].js 可以代表 /posts/a 也可以是 /posts/a/b/posts/a/b/c 等,不过也可以代表 /posts

所以 query 物件会是空物件 {}

注意:query 在 static (静态) 页面在第一次渲染的时候不会有东西,就是一个空物件 {},等到 hydration 完成之後,query 才会被更新

继续到下一个章节之前,我们复习一下~
Next.js Pages & Routing

Client-side Routing

虽然 routing 方式不太一样,不过 Next.js 还是跟 SPA (Single-page Application) 一样可以做 client-side routing,意思是换页的时候浏览器不用重新 reload,使得整个体验非常顺。Next.js 提供两种方法:

  • <Link> (next/link)
  • useRouter (next/router)

next/link 提供 Link component 可以直接用在我们的 react components 里面,跟 react-router-dom 里的 Link 差不多的用法。当我们想要在画面上显示一个连结的时候,可以用 Link,他底层用 HTML 的 a 实作出来的。比较特别的是,当使用者画面上有显示 <Link /> components, Next.js 会把所有采用 SSG / ISR 的页面先做 prefetch (事先抓取) 这些页面的档案与资料,所以当使用者点下其中一个连结,浏览器可以马上显示新的画面不需要等待,提升使用者换页的体验。想要用 Link 有几种方法:

连去 Static Paths

import Link from "next/link"

function Home() {
  return (
    <div>
      <Link href="/">
        <a>Home</a>
      </Link>
      <Link href="/about">
        <a>About</a>
      </Link>
    </div>
  )
}

export default Home

string (字串) 当 href"/" 会连到 pages/index.js 的档案,然後 "/about" 会连到 "pages/about.js" 档案。

连去 Dynamic Paths

import Link from "next/link"

function Posts({ posts }) {
  return (
    <div>
      {posts.map(post => (
        <Link href={`/posts/${post.id}?utm_source=ithome`}>
          <a>Post #{post.id}</a>
        </Link>
      ))}
    </div>
  )
}

export default Posts

想要导页去 dynamic routes 一样可以把 path 组成 stringhref,例如 /posts/${post.id} 然後 post.id 是动态的。或是可以把 path 拆成 object (物件) 给 href,像这样~

{
  pathname: "/posts/[pid]", // 跟 file name 一样
  query: { pid: post.id }, // path 中动态的部分,在这例子是 pid
}

query 不只可以包含 path 中的动态部分,也可以包含 URL 中的 query string,像 /posts/1?utm_source=ithome 这个 path 可以写成:

{
  pathname: "/posts/[pid]",
  query: { pid: post.id, utm_source: "ithome" },
}

useRouter

除了把连结显示在画面上让使用者点下去以外,我们也可以用程序码做导页,就是用 useRouteruseRouter 回传 router 物件,里面包含各式各样与 routing 有关的资讯,例如 pathname (当下的路径), query (该路径的 query string), isFallback (服务器是否正在显示备份版本的页面), isReady (浏览器是否已经拿到 route 相关资讯) 等资讯。不过 router 还包含一些 methods,有几个跟导页有关的:

  • push:导去某个页面
  • replace:导去某个页面可是把目前所在的记录去换掉
  • back:回到上一页

Shallow (浅) Routing

什麽是 shallow routing 或是浅层换页 (浅层路由)?换页的过程中服务器不会重跑 data fetching 的 functions,也不会 re-render (重新渲染) 整个页面保持该页的状态。虽然页面不会被换掉,可是 router 中的 pathnamequery 会拿到最新值。

router.push("/?id=1", undefined, { shallow: true })

不过要注意,shallow routing 只能用在同一个页面,/?id=1 换去 /about?id=1 是不同的页面,所以 Next.js 会跟平常一样去下载新的页面。

Next.js Client-side Routing

小结

File-based routing 是不是看起来很棒呢?~ 不过还是要注意小细节喔,避免遇到 routing 相关问题。明天跟大家分享让 Next.js 变成一个全端框架的原因,就是 API routes!
祝大家中秋节快乐!

晚安 <3

看更多


<<:  Consistency and Consensus (4-1) - Atomic Commit and Two-Phase Commit(2pC)

>>:  Day20 测试写起乃 - $CHILD_STATUS

Kotlin Android 第13天,从 0 到 ML - Activity 和 Activity 生命周期

前言: ConstraintLayout讲完了,画面画好了那是用在那呢? 那就是要放在 Activi...

29 | WordPress 区块编辑器 | 本次教学单元总结:

感谢大家花宝贵的时间阅读这系列的文章,由於篇幅有限,其实还有很多主题无法尽录,不过希望阅读过後,大...

【Day 11】For 回圈

前言 今天要来介绍一点 for 回圈,因为接下来的 list 会用到!会介绍一些基本的 for 的用...

【资料库系统】L2 关联式模型

L2 关联式模型 2-1 关联式模型结构 表(tables):一个关联式资料库包含了表的集合 关联(...

躲开Windows地雷使用AWS的Docker让你上天堂

Container会飞 在AWS ECS上目前有提供EC2 mode, Fargate, ECS A...