iT邦幫忙

2023 iThome 鐵人賽

DAY 26
0
Modern Web

React 走出新手村 系列 第 26

React 走出新手村 — Next SSR

  • 分享至 

  • xImage
  •  

SSR

Next 的 SSR(Server-Side Rendering)的概念是在每個使用者請求時動態產生頁面內容,而不是提前產生靜態 HTML 頁面,這樣頁面可以根據使用者的需求和上下文動態渲染,適用於需要即時資料或使用者特定資訊的場景。

想解決的問題:

  1. 即時數據: 適用於需要即時數據或使用者特定資訊的頁面,例如個人化儀表板、社群媒體的動態內容等。
  2. 更好的 SEO: 搜尋引擎可以爬取動態產生的內容,從而提高搜尋引擎優化(SEO)。

適用場合:

  • 個人化內容:如果頁面的內容根據使用者的登入狀態、位置或其他上下文資訊而變化,SSR 可以實現個人化。
  • 即時數據:適用於需要即時更新的數據,例如股票報價、天氣資訊等。

實作SSR

以下是一個範例來解釋 SSR 模式的精神以及如何使用 Next.js 實作:

// pages/location/index.tsx
import React from 'react'

interface RickandmortyLocation {
  id:	number;
  name:	string;
  type:	string;
  dimension: string;
  residents: string[];
  url: string;
  created: string;
}

interface RickandmortyLocationRes {
  info: {
    count: number,
    pages: number,
    next: string | null,
    prev: string | null,
  },
  results: RickandmortyLocation[]
}

const Location = ({ apiData }:{ apiData: RickandmortyLocationRes}) => {
  return (
    <div>
      <h2>Location Page</h2>
      <div>
        {apiData?.results?.map((locate) => (
          <div key={locate.id}>
            <p>{locate.name}</p>
          </div>
        ))}
      </div>
    </div>
  )
}

export async function getServerSideProps() {
  try{
    const res = await fetch("https://rickandmortyapi.com/api/location");
    if (!res.ok) {
      return { notFound: true };
    }
    const apiData: RickandmortyLocationRes = await res.json();
    return {
      props: {
        apiData,
      },
    };
  } catch(err) {
    console.log('err',err);
  }
}

export default Location

getServerSideProps

getServerSideProps 只會在伺服器端運行並不會在瀏覽器執行,如果這個頁面使用 getServerSideProps,當你直接請求這個頁面時,getServerSideProps在請求的時候運行,這個頁面會和回傳的 props 一起提前渲染。

getServerSideProps 簡化哪些事?

在不透過Next 的情況下要怎麼實現SSR? 假設一個簡單的counter component如下:

// shared/components/Counter.jsx
import { useState } from 'react';

const Counter = () => {
	const [count, setCount] = useState(0);
	const onAdd = () => setCount(count+1);
	return (
		<>
			<p>{count}</p>
			<button onClick={onAdd}>++</button>
		</>
	);
};

透過 server 渲染只能拿到靜態的html

// server/index.js
import ReactDOMServer from "react-dom/server";
import express from "express";
require("node-jsx").install();

const app = express();
app.get("/", (req, res) => {
    const reactHtml = ReactDOMServer.renderToString(<Counter />)
    const htmlTemplate = `
		<!DOCTYPE html>    
		<html>
        <head>
            <title>Universal React server bundle</title>
        </head>
        <body>
            <div id="root">${reactHtml}</div>
            <script src="public/client.bundle.js"></script>
        </body>
    </html>
		`;
    res.send(htmlTemplate)
});

這個時候拿到的 button 是不能動的,老時代的 SSR 作法就到此為止了,但 React 的作法是需要用戶端根據 server 產生的頁面,繼續二次渲染、事件綁定等。

// client/index.jsx
import React from 'react';
import { hydrate } from 'react-dom';

hydrate(<Counter />, document.getElementById('root'));

簡化流程是:

  1. 伺服器器端使用renderToString直接渲染出的頁面信息為靜態html。
  2. 用戶端根據渲染出的靜態html 進行hydrate,做一些綁定事件等操作。

因此,若要使用react 來實現服務端渲染,一般需要3個目錄,工程配置比較繁瑣。

  • server: 包含 express 的後端工程。
  • client: 包含 react 的前端工程。
  • shared: 包含前後端公用的組件。

而使用Next的話,透過 getServerSideProps 就能輕鬆完成上述的工作。

SSR仍存在的問題

  1. 當請求量增大時,每次重新渲染增加了server 的負載。
  2. 需要等頁面中所有 getServerSideProps 請求完成才可以返回 html,雖不是空白頁面,但完成 hydrate 之前,頁面也是不可操作,也就是我架構篇章提到的僵直時間。

給全新手的大禮包

React基本Hook教學

參考資料

Leo大Medium
Next官方文件


上一篇
React 走出新手村 — Next ISR
下一篇
React 走出新手村 — React Server Components
系列文
React 走出新手村 31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言