文章目錄
- 一、什么是 Next.js 的同構?
- 二、核心目錄結構
- 三、關鍵函數:如何實現不同渲染方式?
- 1. getServerSideProps —— 實現 SSR(每次請求動態獲取數據)
- 2. getStaticProps + getStaticPaths —— 實現 SSG(構建時生成)
- 四、Hydration:服務端渲染 + 客戶端交互
- 五、客戶端/服務端代碼混用的注意點
- 六、完整例子:同構頁面流程圖
- 七、總結
在如下文章我們介紹了同構和三大渲染場景:
- WHAT - 前端同構 Isomorphic Javascript
- WHAT - SSR vs SSG vs ISR
接下來我們主要去深入了解 React 的同構實現,Next.js 是最好的起點。它為你封裝好了復雜的同構邏輯,讓你專注于構建組件和頁面。
下面我會幫你系統性地理解 Next.js 的同構機制,包括目錄結構、渲染方式(SSR/SSG/ISR)、客戶端與服務端代碼共存的原理。
一、什么是 Next.js 的同構?
在 Next.js 中,“同構”意味著:
- 你的 React 頁面可以在服務端渲染出 HTML。
- 然后發送給瀏覽器,并在瀏覽器上"水合"成可交互的 React 應用。
一套代碼,同時運行在服務器和瀏覽器,頁面內容和結構一致。
二、核心目錄結構
my-next-app/
├── pages/ # 路由頁面(同構重點)
│ ├── index.tsx # 首頁(自動匹配 / 路由)
│ ├── about.tsx # /about 頁面
│ └── [id].tsx # 動態路由頁面 /xxx
├── public/ # 靜態資源
├── components/ # 可復用的 React 組件
├── styles/ # 樣式文件
└── next.config.js # 配置文件
每個 pages/xxx.tsx
頁面都會被 Next.js 編譯為同構頁面 —— 即同時具有 SSR/CSR 能力。
三、關鍵函數:如何實現不同渲染方式?
1. getServerSideProps —— 實現 SSR(每次請求動態獲取數據)
// pages/post/[id].tsx
export async function getServerSideProps(context) {const res = await fetch(`https://api.example.com/post/${context.params.id}`);const data = await res.json();return { props: { data } };
}
- 每次請求服務器都會運行這段邏輯,返回 HTML。
2. getStaticProps + getStaticPaths —— 實現 SSG(構建時生成)
// pages/post/[id].tsx
export async function getStaticPaths() {const res = await fetch('https://api.example.com/posts');const posts = await res.json();return {paths: posts.map(post => ({ params: { id: post.id.toString() } })),fallback: false, // or 'blocking' for ISR};
}export async function getStaticProps({ params }) {const res = await fetch(`https://api.example.com/post/${params.id}`);const data = await res.json();return { props: { data }, revalidate: 60 }; // ISR:60秒更新一次
}
- 初始構建時預生成頁面,后續請求直接返回靜態 HTML。
- 使用
revalidate
支持增量靜態更新(ISR)。
四、Hydration:服務端渲染 + 客戶端交互
-
服務端階段:
- Next.js 在 Node.js 環境執行頁面組件。
- 使用
react-dom/server
渲染為 HTML。 - 將 HTML 和頁面初始數據一同發送給瀏覽器。
-
客戶端階段:
- React 在瀏覽器中調用
hydrate
方法,把 HTML “接管”。 - 綁定事件、狀態等功能,實現交互。
- React 在瀏覽器中調用
這就是同構的本質:HTML 是 SSR 渲染的,交互是 CSR 接管的。
五、客戶端/服務端代碼混用的注意點
在 Next.js 中你可以寫出這樣的代碼:
import { useEffect } from 'react';export default function Page() {useEffect(() => {console.log('只在瀏覽器中執行');}, []);return <div>Hello World</div>;
}
? 這段代碼在 SSR 階段會忽略 useEffect
,只渲染 HTML
? 到瀏覽器中后,useEffect
會執行,實現動態行為。
如果你需要只在服務端運行邏輯,可以用:
if (typeof window === 'undefined') {// 服務端環境
}
六、完整例子:同構頁面流程圖
User 請求頁面 ──> 服務器運行 React 頁面(SSR) ──> HTML 返回給瀏覽器│帶上初始數據(props)↓瀏覽器加載 React、hydrate 成交互頁面
七、總結
項目 | 是否同構 | 渲染方式 | SEO 支持 | 首屏速度 |
---|---|---|---|---|
React CRA | ? | CSR | ? | 慢 |
Next.js SSR | ? | 服務端渲染 | ? | 快 |
Next.js SSG | ? | 靜態生成 | ? | 非常快 |
Next.js ISR | ? | 靜態 + 動態混合 | ? | 快且智能 |