Next.js 的 pre-rendering 分成两种形式,一种是 SSG (Static Side Generation),另一种是 SSR (Server Side Rendering)。SSG 与 SSR 不一样地方是,SSG 是 next build
打包 HTML 後,每次使用者都会是拿到一样的 HTML。SSR 则是每次使用者浏览页面时,服务器都会重新建立 HTML,会回传新的 HTML 给使用者。
先前我们已经知道怎麽在 Next.js 做 SSG,接下来我们要来了解怎麽在 Next.js 中做 SSR。
getServerSideProps
getServerSideProps
的写法跟 getStaticProps
很相似,一样是在跟 component 同一个档案 export
一个 async
的 function,然後回传的 props
就会注入到 component 中,让 Next.js 帮我们做 SSR:
import { GetServerSideProps } from "next";
export const getServerSideProps: GetServerSideProps = async (context) => {
return {
props: {},
};
};
我们改写前几天有写过的 pages/products/[id].tsx
,把之前的 isFallback
删除,把这个页面当作是 Pure Component,只渲染内容而已:
import { Product as ProductType } from "../../fake-data";
import ProductCard from "../../components/ProductCard";
import { PageTitle, ProductContainer } from "./[id].style";
interface ProductProps {
product: ProductType;
}
const Product = ({ product }: ProductProps) => {
return (
<>
<PageTitle>商品详细页面</PageTitle>
<ProductContainer>
<ProductCard product={product} all />
</ProductContainer>
</>
);
};
export default Product;
接着,我们看到怎麽在元件中写 getServerSideProps
,首先我们呼叫 fake API,因为这个 function 也是 async
所以可以使用 await
的关键字等待 fetch
回传结果,然後再转换成 JSON 格式传到 component 中。
import { GetServerSideProps } from "next";
import { ParsedUrlQuery } from "querystring";
// react component
interface Params extends ParsedUrlQuery {
id: string;
}
export const getStaticProps: GetServerSideProps<ProductProps, Params> = async ({
params,
}) => {
// params! 是用来断言 params 一定不是 null 或 undefined
const api = `https://fakestoreapi.com/products/${params!.id}`;
const res = await fetch(api);
const json: ProductType = await res.json();
return {
props: { product: json },
};
};
读者应该会发现 GetServerSideProps
多了两个 generic type,分别为 ProductProps
与 Params
,ProductProps
被用於定义回传 props
的型别,而 Params
则是用来定义 url 中 query string 的型别。
先前我们使用 file-based routing 中提过,由档案的名称定义路由可以符合多种形式,所以 params
可能会有多种的型别,接下来我们要来查找它在 Next.js 中的型别是什麽?
我们直接从 Next.js 的 GetServerSideProps
往里面追 params
的型别定义,会看到它的型别继承了 ParsedUrlQuery
:
export type GetServerSidePropsContext<
Q extends ParsedUrlQuery = ParsedUrlQuery
> = {
params?: Q;
};
然後,继续往下追 ParsedUrlQuery
的型别定义是 string
或 string[]
:
interface ParsedUrlQuery extends NodeJS.Dict<string | string[]> {}
现在我们可以知道 params
的型别有可能会是 string
、 string[]
或是 undefined
其中一种,所以在使用 params
这个物件时可以为它撰写型别,让程序码更严谨,像是上述的范例中定义 id: string
。
getServerSideProps
?根据 Next.js 官方说明,如果需要每次使用者浏览网页时,服务器都能呼叫 API,将最新的资料都注入到 HTML,则可以选择使用 getServerSideProps
。否则,如果不在意使用者是否拿到最新的资料,可以考虑使用 getStaticProps
。
如果以成本面来看,由於 SSG 不需要每次使用者浏览页面时都重新执行 getStaticProps
,可以直接回传静态的 HTML 给使用者,甚至可以仰赖 CDN 的 cache 大量减少服务器的成本。反之, getServerSideProps
每次使用者浏览一个页面时时都要让服务器执行 getServeSideProps
中的程序码,如果大多数页面都是 SSR 将会对服务器造成负担。
再从使用者体验的观点来看,SSG 除非是设定 fallback: 'blocking'
,否则使用者在 SSG 的页面看到内容的平均速度会比 SSR 更快,会导致 web vitals 的其中一项指标 Time to First Byte (TTFB) 在 SSG 页面的表现比较好。
最後,我们来谈谈 Automatic Static Optimization 这项功能。
在 Next.js 中除了自己撰写 getStaticProps
或 getServerSideProps
决定一个页面是 SSG 或 SSR 之外,它可以自动化分析一个页面是不是有依赖一些 API 的资料回传,如果没有的话,这个页面在不用加上 getStaticProps
或 getServerSideProps
的情况下,就可以获得 pre-rendering 的好处。
以下是一个一简页面,虽然没有写 getStaticProps
或 getServerSideProps
这两个 function,但是从网页的原始中可以看到 <div>
里面是有字的,与原生的 React 一开始都只会给予空的节点是不一样的。
function Page() {
return (
<div>
<div>Next.js</div>
<div>Next.js</div>
<div>Next.js</div>
</div>
);
}
export default Page;
在 Automatic Static Optimization 後,Next.js 会在 next build
的阶段为符合的页面产生 .html
档案,假设上方范例的页面是 pages/home.tsx
,所以就会产生对应的 HTML 档案:
.next/server/pages/home.html
但如果加上了 getSererSideProps
或是 getInitialProps
,则页面就会变成 .js
档案:
.next/server/pages/home.js
要触发这个自动优化的功能,页面不能加上 getSererSideProps
或是 getInitialProps
,亦即该页面不是走 SSR 的流程。
再者,如果在专案中的 Custom App _app.ts
中使用 getInitialProps
,将会导致整个专案的自动优化功能消失。
例如以下便是让自动优化消失的范例:
import "../styles/globals.css";
import App, { AppProps, AppContext } from "next/app";
function MyApp({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />;
}
MyApp.getInitialProps = async (appContext: AppContext) => {
const appProps = await App.getInitialProps(appContext);
return { ...appProps };
};
export default MyApp;
在这篇文章中我们知道在 Next.js 中使用 SSR 必须使用 getServerSideProps
,如此一来就可以让使用者在浏览网页时都能够拿到最新的资讯。但是 Next.js 官方说到如果没有「使用者必须拿到最新资料」的需求,则是推荐使用 getStaticProps
,因为不论是以使用者体验或是成本面,SSG 的效果都比 SSR 更好。
而且 Next.js 甚至有自动化分析页面是否可以进行 SSG,不用撰写 getStaticProps
就可以让页面拥有 SSG 的优点,所以读者在使用 Next.js 时也能够以 SSG 为优先考量,如果有上述需求时再使用 SSR 撰写页面。
<<: 【设计+切版30天实作】|Day10 - 因应Bootstrap的元件去弹性设计Reviews区块
INSERT 基本语法 INSERT INTO '资料表名称'('栏位名称1','栏位名称2',.....
作者认为,认为一件事物无法量测,理由有三个面向: 衡量的观念:按照昨天的摘要,最大的误会是人们常常觉...
一、究竟AI能不能预测股价? 不能 好了,被我骗进来的可以按上一页了(X 结论已经讲了,如果你对原因...
不过让我印象最深刻的面试就是yahoo所委托的专案 那时候委托者是需要做出一个yahoo news...
还记得第2天在做专案规划时,有提到一个目标「加密敏感资料实现资安管理」吗? 目前我们的密码还是一样...