next.js - SSR

SSR, server side rendering.

CSR vs SSR vs SSG

  • CSR (Client Side Rendering)

    • 網頁起始無內容,在網頁 mounted 後才取得內容。故SEO無效因為搜尋引擎看不到商品目錄。

    • 適合資訊不公開等保密性較高的應用。

  • SSR (Server Side Rendering)

    • 於 request 時決定了網頁起始內容。SEO有效。網頁內容在操作後可變動,即商品目錄可下查詢條件而變動。

    • 適合有商品目錄類的應用。

  • SSG (Static Side Generation)

    • 於 build/bundle 時期決定了內容,產出全靜態網站。SEO有效。因為是靜態屬性所以內容無法變更,即商品目錄無法變動頂多隱藏或顯示。

    • 適合海報、廣告類的應用。

getServerSideProps

getServerSideProps重點整理

Next.js的SSR能力是透過此函式getServerSideProps實作。下面列出幾個要點:

  1. 此函式只會在 Server Side 執行。

  2. 此函式內的內容不會送到前端。

  3. 此函式可以取用後端全部資源,包含後端檔案讀寫與DB Access。

  4. 此函式只在網頁 "page" 進入點有效。如:pages/index.tsx

  5. 此函式在每次 request 都會觸發。

程式碼紀錄

pages/dm0010/index.tsx
import type { NextPage } from 'next'
import type { Commodity } from './interfaces'
import Head from 'next/head'
import AppForm from './AppForm'
import { qryCommodityList } from './bizLogic'

const DM0010Page: NextPage<{
  commodityList: Commodity[] // 商品目錄將從 props 送進來。
}> = (props) => {
  return (
    <>
      <Head>
        <title>DM0010</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>
      {/* 將商品目錄往子層送進去 */}
      <AppForm {...props} />
    </>
  )
}

export default DM0010Page

/// SSR with dynamic parameters
/// 此函式只在 page 進入點有效。
export async function getServerSideProps(context) {
  // 解析URL Query參數:http://localhost:3000/demo/dm0010?category=運動
  const { query: { category } } = context
  // 查詢商品目錄
  const commodityList = qryCommodityList(category) 
  // 商品目錄將從 props 送進去。
  return {
    props: {
      commodityList
    }
  }
}
pages/dm0010/AppForm.tsx
import type { Commodity } from './interfaces'
import { useState } from 'react'
import { qryCommodityList } from './bizLogic'

export default (props: {
    commodityList: Commodity[] // 初始商品目錄將從props送進來。
}) => {
    // 初始商品目錄來自SSR模式,從props送進來。
    const [commodityList, setCommodityList] = useState<Commodity[]>(props.commodityList)

    // 之後操作查詢商品目錄來自CSR模式。
    function handleQuery() {
        const commodityList = qryCommodityList('other')
        setCommodityList(commodityList)
    }

    return (
        <div>
            <h1>DM0010: SSR 練習</h1>
            <button onClick={handleQuery}>查詢</button>
            <h2>模擬商品清單</h2>
            <ul>
                {Array.isArray(commodityList) && commodityList.map((item, index) => (
                    <li key={index}>
                        {`${item.cid}-${item.cname} 數量 ${item.amount} | ${item.category}`}
                    </li>
                ))}
            </ul>
        </div>
    )
}
pages/dm0010/bizLogic.ts
import type { Commodity } from './interfaces'
import db from './db.json'

/// 模擬自DB主機取值
export function qryCommodityList(category: string): Commodity[] {
  return db.commodityList.filter(c => !category || c.category === category)
}t
pages/dm0010/interfaces.ts
export interface Commodity {
  cid: string,
  cname: string,
  amount: number,
  category: string,
}
pages/dm0010/db.json
// 模擬商品目錄
{"commodityList":[
  {"cid":"C00","cname":"商品0號","category":"運動","amount":1000},
  {"cid":"C01","cname":"商品1號","category":"運動","amount":17},
  {"cid":"C02","cname":"商品2號","category":"文書","amount":21},
  {"cid":"C03","cname":"商品3號","category":"文書","amount":390},
  {"cid":"C04","cname":"商品4號","category":"文書","amount":434},
  {"cid":"C05","cname":"商品5號","category":"文書","amount":5},
  {"cid":"C06","cname":"商品6號","category":"文書","amount":6},
  {"cid":"C07","cname":"商品7號","category":"運動","amount":7},
  {"cid":"C08","cname":"商品8號","category":"other","amount":87},
  {"cid":"C09","cname":"商品9號","category":"運動","amount":93},
  {"cid":"C10","cname":"商品10號","category":"運動","amount":102}
]}

沒圖沒真象

測試網址:http://localhost:3000/demo/dm0010?category=文書

產生畫面如下,簡易的商品清單。

解析產生的 html 碼中可以看到商品目錄訊息,這在CSR模式下是看不到的。

EOF

Last updated