Next.js 基礎功能實作
Create a Next.js App
使用 create-next-app 建立 Next.js app
npx create-next-app@latest
# or
yarn create next-app
# or
pnpm create next-app
安裝 next
, react
and react-dom
packages
npm install next react react-dom
# or
yarn add next react react-dom
# or
pnpm add next react react-dom
在 package.json
中添加 scripts
:
"scripts": {
"dev": "next dev", // to start Next.js in development mode
"build": "next build", // to build the application for production usage
"start": "next start", // to start a Next.js production server
"lint": "next lint" // to set up Next.js' built-in ESLint configuration
}
Navigate Between Pages
Page in Next.js
/pages
文件夾是用於創建應用程式頁面的地方。在 /pages
文件夾中,每個檔案可以導出一個 React component,這個 component 將用於渲染相應的頁面,而每個檔案名稱代表一個 URL 路徑。例如,pages/index.js
檔案將處理應用程式的根路徑 /
。
/pages
文件夾內的結構和命名方式也具有一定的規範。例如,pages/posts/first-post.js
,就會創建一個路徑為 /posts/first-post
的頁面。同時,pages/index.js
文件是應用程式的首頁,也就是應用程式的根路徑 /
。
Link Component
Next.js 的 Link
component 是一個內置的 React component(next/link),用於在 Next.js 應用程式中實現客戶端路由,意味著頁面轉換使用 JavaScript 進行,這比瀏覽器完成的默認導航更快。。它可以幫助我們在不刷新整個頁面的情況下切換頁面,從而提供更好的用戶體驗。Link component 在使用時需要指定 href 屬性,該屬性指定頁面的 URL。當用戶點擊 Link component時,Next.js 將通過內部路由系統切換到新的頁面,而無需重新加載整個應用程式。
import Link from 'next/link'
function IndexPage() {
return (
<div>
<h1>歡迎來到首頁</h1>
<Link href="/about">
<a>關於我們</a>
</Link>
</div>
)
}
export default IndexPage
Next.js 自動進行 code splitting
,因此每個頁面只加載該頁面所需的內容。這確保即使有數百個頁面,主頁也能快速加載。
僅加載請求的頁面程式碼也意味著頁面間互相獨立。如果某個頁面拋出錯誤,應用程式的其餘部分仍然可以工作。此外,在 product 階段,當 Link component 出現在瀏覽器中時,Next.js 會自動在後台預取(prefetching
) Link 連接頁面的程式碼。點擊連結時,目標頁面的程式碼已經加載完成,可以達到更即時的頁面轉換。
Assets, Metadata, and CSS
在 Next.js 中,靜態資源集中於 /public
文件夾中。/public
中的文件可以從類似於頁面的應用的根目錄中引用。如以下範例,可在其他頁面引用:
<img src="/images/profile.jpg" alt="Your Name" />
Image Component and Image Optimization
Next.js 的 next/image 是 HTML <img>
元素的擴展,提供了Image Component ,是一個可優化圖像載入效能的 React 組件。使用 Image Component
載入圖片可以帶來幾個好處:
- 自動優化圖片大小:使用 Image Component 可以自動優化圖片的大小,減少圖片載入時間,提高網頁性能。
- 支援多種格式:Image Component 支援多種圖片格式,包括 JPEG、PNG、WebP 等。這可以確保瀏覽器可以載入最適合的格式,進一步提高載入速度。
- 自動選擇最佳的圖片大小:Image Component 可以根據不同螢幕大小自動選擇最佳的圖片大小,這可以確保圖片不會在大螢幕下變得模糊,也不會在小螢幕下佔用過多空間。
import Image from 'next/image';
function MyComponent() {
return (
<div>
<Image
src="/my-image.jpg"
alt="My Image"
width={500}
height={500}
/>
</div>
);
}
Next.js 的 Image Component
不是在建置時自動優化圖片,而是當使用者訪問網頁時動態地優化圖片。這種做法避免了在建置時將大量的圖片進行處理和儲存所需的時間和資源。相反,只有在需要時才會進行圖片優化和載入,從而提高了性能和減少了網頁載入時間。
Image Component
預設啟用了 lazy loaded
,這意味著在畫面外的圖片不會立即載入,而是當它們進入視窗範圍時才會載入。這有助於減少網頁載入時間和頁面速度的提高。此外,Image Component
還可以避免累積版面位移 (Cumulative Layout Shift),這是 Google 將在搜索排名中使用的一種核心網頁指標。這通常是因為網頁中的圖片尺寸未指定或未經優化而導致的。但是,Image Component 會在圖片載入之前,確定圖片的尺寸和佔位符,以避免任何版面位移。
CSS Modules
CSS Modules 是一種用於管理 CSS 的技術,它的主要目的是解決 CSS 命名衝突的問題。在傳統的 CSS 中,當開發者編寫樣式時,往往會使用全域命名,這樣容易導致樣式的污染和命名衝突。而 CSS Modules 可以讓開發者在組件級別上創建作用域,從而避免了命名衝突的問題。
CSS Modules 的基本思想是將 CSS 文件編譯成一個 object,然後在 JavaScript 中引用這個 object,這樣可以在 JavaScript 中訪問 CSS 樣式,並在運行時將 CSS 樣式應用到元素上。編譯後的對象中,每個 CSS 樣式都有一個唯一的名稱,因此不會發生命名衝突的問題。在 Next.js 中,使用 CSS Modules 還可以享受到 code splitting
的好處。code splitting
可以將每個頁面所需的最小化的 CSS 加載,從而減少了頁面的加載時間和網頁大小。這種方式適用於大型應用程序,因為它可以大大提高性能和網頁速度。
import styles from './layout.module.css';
export default function Layout({ children }) {
return <div className={styles.container}>{children}</div>;
}
要使用 CSS Modules,CSS 文件名必須以 .module.css 結尾。
Global Styles
CSS Modules 對於 component-level style 很有用,但若想把 CSS 添加到每一個頁面上則可以使用 Global Styles
。在 Next.js 中,Global Styles
是指在整個應用程式中都會使用的樣式,使用 Global Styles 可以讓整個應用程式的外觀看起來更統一,並且減少在各個頁面上都要引入相同樣式的重複程式碼。
在 /pages
目錄下建立一個名為 _app.js
的檔案,並在裡面引入需要的 CSS 檔案。
import '../styles/global.css'
function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
export default MyApp
Pre-rendering and Data Fetching
Pre-rendering
Next.js 預設會進行預渲染 (pre-rendering
),也就是事先將每個頁面產生 HTML 檔案,而不是讓客戶端的 JavaScript 進行渲染。透過預渲染,可以提高網站的效能和搜尋引擎最佳化 (SEO)。每個產生的 HTML 檔案都會關聯到該頁面所需的最小 JavaScript 程式碼。當網頁被瀏覽器載入時,與該頁面相關連的 JavaScript 程式碼會運行。(這個過程稱為 hydration)。
SSR 與 SG 兩種 Pre-rendering
Next.js 中提供了兩種不同的預渲染方法:Static Generation (SG)
與 Server-Side Rendering (SSR)
。重要的是 ,Next.js 允許我們選擇每個頁面要使用的 Pre-render 方法,我們可以在部分頁面用 SG
, 在部分頁面用 SSR
。Next.js 官方建議:無論頁面上是否有 data, 盡可能用 SG
。因為這樣頁面只需要在 build 階段編譯,而且可以用 CDN 伺服器儲存頁面資訊,這會比 SSR
還快很多。
Static Generation
是在建置時先生成 HTML 檔案,之後每次接到 request 時就可以直接重複使用這些 HTML,不需要再重新生成。Server-Side Rendering(SSR)
則是每次接到 request 時都會即時生成 HTML,然後再回傳給使用者。
在選擇 pre-rendering 方式時,可以問自己:
“我能在使用者發出 request 之前預先渲染這個頁面嗎?”如果答案是肯定的,那麼就應該選擇 SG
。
另一方面,如果無法在使用者發出請求之前預先渲染頁面,那麼 SG
就不是一個好主意。若頁面顯示的是經常更新的數據,並且頁面內容在每次請求時都會變化。那 SSR
會是比較好的選擇。
使用 getStaticProps 實現 SG
有些網頁的內容需要在 build 階段先從外部獲取數據,例如從文件系統中讀取文件、從外部API中獲取數據,或者數據庫中查詢數據。對於這種情況,Next.js 提供了一種方法,稱為 Static Generation with data,即支持在 build
時預先獲取外部數據並生成HTML頁面。
在 Next.js 中,getStaticProps
是一個用來提前獲取數據的函數。它可以在構建時靜態生成頁面所需要的數據,並將其作為 props 傳遞給頁面。這樣,當用戶訪問頁面時,就可以直接使用先前生成的數據,而不必再次獲取。
使用 getStaticProps
可以實現靜態生成具有動態數據的頁面。例如,你可以從 API 或數據庫中獲取數據,並在構建時生成 HTML,以便在用戶訪問頁面時快速加載。
以下是使用 getStaticProps
的示例:
export async function getStaticProps() {
// Fetch data from external API
const res = await fetch('https://api.example.com/data')
const data = await res.json()
// Pass data as props
return {
props: {
data
}
}
}
function MyPage({ data }) {
// Render data...
}
export default MyPage
在上面的示例中,getStaticProps 函數會從外部 API 獲取數據,然後將其作為 data 屬性傳遞給 MyPage
component。當用戶訪問 MyPage
頁面時,Next.js 會直接使用之前生成的數據,而不必再次從 API 獲取數據。使用 getStaticProps
的好處是可以在每次重新生成網站時自動更新網站內容。例如,當網站上的產品頁面需要更新時,只需更新數據庫中的數據,然後重新生成網站即可。
使用 getStaticProps
可以告訴 Next.js 哪些頁面具有數據依賴關係,在構建時預先解析這些依賴關係。
需要注意的是,在 dev mode
下,getStaticProps
會在每次請求時運行,而不只在 build 期間運行。
除了從外部 API 獲取資料,getStaticProps
也可以直接跟 database 要資料,因為 getStaticProps
僅在伺服器端運行。它永遠不會在客戶端運行。它甚至不會包含在瀏覽器的 JS 包中。
import someDatabaseSDK from 'someDatabaseSDK'
const databaseClient = someDatabaseSDK.createClient(...)
export async function getSortedPostsData() {
// Instead of the file system,
// fetch post data from a database
return databaseClient.query('SELECT posts...')
}