Skip to main content

[nextjs] Getting Started

TD;DR#

$ npx create-next-app nextjs-blog --use-npm --example "https://github.com/vercel/next-learn-starter/tree/master/learn-starter"

Navigation#

Routing

  • Next.js 會自動處理 code splitting、client-side navigation 和 prefetching(production 時)的功能
    • code splitting 指的是只會下載使用者有用到的(有檢視到的)頁面
    • client-side navigation 表示它不是真正透過 HTTP Request 來達到換頁的,而是透過 JavaScript 讓使用者所看到的頁面改變
    • prefetching 指的是 next.js 會根據該頁 <Link /> 中有用到的頁面,預先把檔案下載下來,減少使用者在頁面切換間所需等待的時間
  • 如果希望在連結上添加 HTML 屬性,例如 className,需要加在 <Link /> 元件中的 <a /> 元素,而不是放在 <Link /> 上:
// https://github.com/vercel/next-learn-starter/blob/master/snippets/link-classname-example.js
import Link from 'next/link';
export default function LinkClassnameExample() {
// To add attributes like className, target, rel, etc.
// add them to the <a> tag, not to the <Link> tag.
return (
<Link href="/">
<a className="foo" target="_blank" rel="noopener noreferrer">
Hello World
</a>
</Link>
);
}

Assets, Metadata, and CSS#

Assets#

keywords: <Image />#
  • 靜態檔案會放在 /public 資料夾中。

  • 透過 Next.js 提供的 Image 元件,可以自動

    • 根據不同的螢幕尺寸來 responsive 的顯示圖片
    • 最佳化圖片(變更尺寸、最佳化、在瀏覽器支援的情況下使用 WebP)
    • 只有在圖片進入 viewport 時才下載該圖片
  • 既使圖片是來自外部(例如,CMS),Next.js 一樣可以針對這些圖片進行優化;此外,Next.js 會在圖片需要被使用時(例如,瀏覽器發送請求時)才進行優化的動作,而非在 build-time 就把圖片都處理完,因此不會因為圖片的數量變多而使得 build time 的時間增加。

Metadata#

keywords: <Head />#

Customize Document @ Next.js > Docs > Advanced Features

  • 透過 Next.js 提供的 <Head /> 元件,可以改變 HTML 頁面中 <head /> 的內容。

CSS Styling#

  • 在 Next.js 中預設就支援 CSS Modules、SASS 和 styled-jsx 的寫法,若有需要也可以使用 styled-components、emotion、Tailwind CSS 等等。
  • 若需要使用全域的 CSS 樣式,需要建立 pages/_app.js 這支檔案。這支檔案將會是最上層的元件,可以橫跨不同的頁面:
// pages/_app.js
export default function App({ Component, pageProps }) {
return <Component {...pageProps} />;
}
caution

當新增 pages/_app.js 的檔案後,需要重新啟動伺服器。

note

App 元件因為是所有元件的最上層,因此除了可以用來作為全域的 CSS 樣式使用外,也可以用來保存全域的狀態。

  • 建立全域的 CSS 樣式,在根目錄建立 styles 資料夾,並在裡面建立 global.css 的檔案:
/* styles/global.css */
html,
body {
/* ... */
}
  • 最後在 pages/_app.jsimport 全域的 CSS 樣式:
import '../styles/global.css';
export default function App({ Component, pageProps }) {
return <Component {...pageProps} />;
}
caution

全域的 CSS 樣式只能在 pages/_app.js 中被載入,否則它可能會無預期的影響到其他頁面。

Pre-rendering and Data Fetching#

Pre-rendering and Data Fetching @ next.js > basic

根據資料的使用選擇不同的 render 方法:

  • SSG:畫面(HTML)/資料能夠在 build-time 時就取得(不論是來自 fetch, database 或實體檔案),並且不會每次 request 都改變,畫面在 build time 時就已經建立好,建議大部分情況使用。使用 getStaticProps
  • SSR:畫面(HTML)/資料能夠在 pre-render 時(即,每次收到 request 時)取得,且每次內容都會不同。使用 getServerSideProps
  • CSR:資料不需要 pre-render 時,像是 Dashboard 這類不需要考慮 SEO 的情況。畫面完全由 JavaScript 產生。

Hydration#

預設的情況下,Next.js 會 pre-render 所以頁面,也就是會預先針對每個 Page 產生對應的 HTML,而非透過 client-side JavaScript 來做這件事,以此達到個好的效能和 SEO。

每一個產生好的 HTML 頁面都會伴隨部分的 JavaScript,當一個頁面被瀏覽器載入後,這些 JavaScript 的程式碼會執行,以讓頁面能夠帶有完整的互動功能(這個過程稱作,hydration

Static Site Generation (SSG) 和 Server-side Rendering (SSR)#

實際上,Pre-rendering 分成兩種形式,分別式 Static Generation(SSG / Static Site Generation)Server-side Rendering(SSR)這兩者間最重要的差別是靜態頁面(HTML)產生的時間點

tip

SSR 和 SSG 兩者最大的差別是靜態頁面生成的時間點。

  • Static Generation:靜態頁面是在 build-time 時就產生,伺服器收到 request 時重複使用這些已經生成好的靜態頁面。
  • Server-side Rendering:伺服器每次收到請求時在產生對應的靜態頁面。
note

在開發模式(development mode)下,Next.js 都會採用 Server-side Rendering,即是你設定使用的是 SSG。

在 Next.js 中,可以根據每個頁面選擇要使用 SSG 或 SSR,不一定要全站統一。

SSG 和 SSR 的選擇#

一般來說,不論頁面中有沒有資料存在,都會建議使用 Static Generation(SSG),因為頁面只需要建立一次後,就可以透過 CDN 來提供,速度會比 SSR 來得更快。

tip

只要你認為這個頁面可以是在瀏覽器發送請求前就先產生好的話,就使用 SSG。

除非你的頁面的資料會有頻繁的更新,且內容會根據每次的請求而有不同時,在這種情況下就可以選擇使用 SSR。

Static Generation with Data#

keywords: getStaticProps#
  • 當你在匯出一個 Page 時,可以同時匯出一個名為 getStaticProps 的 async 函式,這個函式將會在 build time 時(production mode)被執行,透過這個名為 getStaticProps 的 function,等同於是告訴 Next.js 說:「這個頁面需要相依於某些外部的資料,因此當 pre-render 此頁面時,需先確定已經取得這些資料(resolve)」。
  • getStaticProps 是一個 async 的函式,你可以在這個 function 中去 fetch 外部的資料,並且把它當成 props 灌入頁面中。
  • getStaticProps 的內容只會在 server-side 被執行,並不會在 client-side 被執行,也不會被打包進傳送到瀏覽器端的 JS 檔,因此你也可以在這裡直接建立與 Database 間的連線。
      • 由於 getStaticProps 這個函式的目的是在 build time 時執行,因此你不能使用那些只有在發送請求後才能取得的資料,像是 query parameters 或 HTTP headers。
  • getStaticProps 只能從 Page 元件被 export
note

在開發模式下,getStaticProps 會在每次收到 request 時被執行。

Fetching Data at Request Time(SSR)#

keywords: getServerSideProps#

若你需要的資料無法在 build time 時就取得,那麼應該考慮使用 SSR 的方式,這時候會用到的方法是 getServerSideProps 而不是 getStaticProps

Client-side Rendering#

如果你不需要在 pre-render 時就帶入資料,那麼則可以考慮使用 client-side rendering。Next.js 團隊有寫了 SWR 這個套件可以參考。

Dynamic Routes#

Dynamic Routes @ next.js > basic

  • 使用 getStaticPaths() 把所有 dynamic routes 的 key 透過 paths 給入
  • 使用 getStaticProps() 把 path 中透過 params 傳進來的參數來取得該頁面的資料內容
// pages/posts/[id].js
// 使用 `getStaticPaths()` 把所有 dynamic routes 的 key 透過 `paths` 給入
export async function getStaticPaths() {
const paths = getAllPostsIds();
return {
paths,
fallback: false,
};
}
// 使用 `getStaticProps()` 把 path 中透過 `params` 傳進來的參數來取得該頁面的資料內容
export async function getStaticProps({ params }) {
const postData = await getPostData(params.id);
return {
props: {
postData,
},
};
}
export default function Post({ postData }) {
// ...
}

API Routes#

API Routes @ Next.js > Docs

API Routes 的目的是透過 Next.js 來寫 API endpoint,類似 express 撰寫的 API endpoint 一樣,可以根據不同的 request 回傳不同的 response。

TypeScript#

在根目錄新增一支 tsconfig.json 的檔案。接著再啟動專案時,Next.js 即會在終端機中提示要安裝的其他套件。

Last updated on