1.?Next.js 概述
Next.js 是一個基于 React 的開源框架,專注于服務器端渲染(SSR)和靜態站點生成(SSG),提供開箱即用的 SSR 功能,簡化 React 應用的開發與部署。
2.?Next.js 的核心特性
-
SSR 支持:默認支持服務端渲染,提高應用性能和 SEO。
-
靜態站點生成(SSG):預渲染頁面,提高加載速度。
-
路由自動生成:基于文件系統的路由生成,無需手動配置。【約定式路由 vs 配置式路由】
-
API 路由:內置 API 路由功能,支持構建后端服務。
-
代碼拆分:自動進行代碼分割,優化加載性能。
-
開發體驗:內置熱重載(HMR)、錯誤處理等,提升開發效率。
3.?安裝與創建 Next.js 項目
使用命令行工具快速創建 Next.js 項目:
npx create-next-app my-next-app
按照提示選擇項目配置,如 TypeScript 支持、ESLint 等。
4. 項目結構解析
my-next-app/├── pages/ // 頁面組件,Next.js 根據此目錄生成路由│ ├── index.js // 對應 / 路徑│ ├── about.js // 對應 /about│ └── ...├── public/ // 靜態文件,直接映射到應用的根路徑├── styles/ // 樣式文件├── components/ // 可復用的 React 組件├── api/ // API 路由├── next.config.js // Next.js 配置文件├── package.json└── ...
5.?路由與頁面
基于文件系統的路由:
-
pages/index.js 對應 /
-
pages/about.js 對應 /about
-
pages/blog/[id].js 對應動態路由 /blog/:id
// pages/index.js
import React from 'react';const Home = () => (<div><h1>首頁</h1></div>
);export default Home;
6.?組件與布局
-
組件(Components):可復用的 React 組件,放在 components/ 目錄。
-
布局(Layouts):定義頁面的整體結構,如導航欄、頁腳等。
// components/Layout.js
import React from 'react';
import Link from 'next/link';const Layout = ({ children }) => (<div><nav><Link href="/">首頁</Link><Link href="/about">關于</Link></nav><main>{children}</main><footer>? 2024 My Website</footer></div>
);export default Layout;
在頁面中使用布局:
// pages/index.js
import React from 'react';
import Layout from '../components/Layout';const Home = () => (<Layout><h1>首頁</h1><p>歡迎來到我的網站!</p></Layout>
);export default
7.?數據獲取
7.1.?getStaticProps(靜態生成)
在構建時獲取數據,生成靜態頁面,適用于數據不經常變化的頁面。
// pages/posts.js
import React from 'react';export async function getStaticProps() {const res = await fetch('https://api.example.com/posts');const posts = await res.json();return {props: {posts,},};
}const Posts = ({ posts }) => (<div><h1>博客文章</h1><ul>{posts.map(post => (<li key={post.id}>{post.title}</li>))}</ul></div>
);export default Posts;
7.2.?getServerSideProps(服務器端渲染)
每次請求時獲取數據,生成頁面,適用于需要實時數據的頁面。
// pages/profile.js
import React from 'react';export async function getServerSideProps(context) {const res = await fetch(`https://api.example.com/user/${context.params.id}`);const user = await res.json();return {props: {user,},};
}const Profile = ({ user }) => (<div><h1>{user.name} 的個人資料</h1><p>郵箱: {user.email}</p></div>
);export default Profile;
8.?中間件與插件
8.1.?中間件
在請求處理鏈中執行的函數,用于權限校驗、日志記錄等。
// middleware/auth.js
export function authMiddleware(req, res, next) {if (!req.user) {res.redirect('/login');} else {next();}
}
8.2.?插件
擴展 Next.js 或 React 的功能,如集成第三方庫,通常通過 npm 包或自定義代碼實現。
示例:集成 Axios
1. 安裝Axios
npm install axios
2. 封裝成插件
// lib/axios.js
import axios from 'axios';const instance = axios.create({baseURL: 'https://api.example.com',
});export default instance;
3.?在頁面中使用
// pages/posts.js
import React from 'react';
import axios from '../lib/axios';export async function getServerSideProps() {const res = await axios.get('/posts');const posts = res.data;return {props: {posts,},};
}const Posts = ({ posts }) => (<div><h1>博客文章</h1><ul>{posts.map(post => (<li key={post.id}>{post.title}</li>))}</ul></div>
);export default Posts;
9.?動態路由與嵌套路由
9.1.?動態路由參數
使用方括號定義動態參數,可通過 context.params 獲取參數值。
// pages/blog/[id].js
import React from 'react';export async function getServerSideProps(context) {const { id } = context.params;const res = await fetch(`https://api.example.com/posts/${id}`);const post = await res.json();return {props: {post,},};
}const Post = ({ post }) => (<div><h1>{post.title}</h1><p>{post.content}</p></div>
);export default Post;
9.2.?嵌套路由
使用目錄結構定義嵌套路由,在父組件中使用 <Outlet />(React Router)或嵌套頁面結構。
// pages/dashboard/index.js
import React from 'react';
import Link from 'next/link';
import { Outlet } from 'react-router-dom';const Dashboard = () => (<div><h1>儀表盤</h1><ul><li><Link href="/dashboard/settings">設置</Link></li><li><Link href="/dashboard/profile">個人資料</Link></li></ul><Outlet /> {/* 這里使用 Outlet 來渲染子頁面 */}</div>
);export default Dashboard;
pages/dashboard/settings.js:
// pages/dashboard/settings.js
import React from 'react';const Settings = () => (<div><h1>設置</h1><p>這里是設置頁面。</p></div>
);export default Settings;
pages/dashboard/profile.js:
// pages/dashboard/profile.js
import React from 'react';const Profile = () => (<div><h1>個人資料</h1><p>這里是個人資料頁面。</p></div>
);export default Profile;
10.?SEO 優化
10.1.?Meta 標簽管理
使用 next/head 組件定義頁面的標題和 meta 信息。
// pages/about.js
import React from 'react';
import Head from 'next/head';const About = () => (<div><Head><title>關于我們 - My Website</title><meta name="description" content="這是關于我們的頁面。" /></Head><h1>關于我們</h1><p>這里是關于我們的內容。</p></div>
);export default About;
10.2.?站點地圖
使用 next-sitemap 等插件自動生成站點地圖。
安裝:
npm install next-sitemap
配置:
// next-sitemap.js
module.exports = {siteUrl: 'https://www.example.com',generateRobotsTxt: true,
};
生成:
npx next-sitemap
11.?部署 Next.js 應用
11.1.?服務器渲染模式部署
需要一個 Node.js 服務器運行 Next.js 應用。
1.?構建應用
npm run build
2.?啟動應用
npm start
11.2.??靜態站點生成
生成靜態的 HTML 文件,部署到靜態服務器,適用于內容不經常變化的站點。
1.?生成靜態文件
npm run export
2.?部署 out/ 目錄內容到靜態服務器
11.3.?云平臺部署
-
Vercel: Next.js 官方推薦平臺,支持無縫部署。
-
Netlify、AWS、Heroku 等也支持部署 Next.js 應用。
12.?性能優化
-
代碼拆分:利用 Next.js 的自動代碼拆分,按需加載組件。
-
緩存:使用 CDN 緩存靜態資源,優化 API 請求。
-
圖片優化:使用 Next.js 內置的 next/image 組件,自動優化圖片。
-
懶加載:延遲加載非關鍵資源,提升首屏加載速度。
示例:使用 next/image
import Image from 'next/image';const Home = () => (<div><h1>首頁</h1><Image src="/logo.png" alt="Logo" width={200} height={200} /></div>
);export default Home;
13.?Next 原理淺析
13.1.?Next 工作流程
13.1.1.?編譯階段
1. 路由生成:掃描 pages/ 目錄,生成路由配置。
2. 模板編譯:將 React 組件模板編譯為渲染函數。
3. 打包:使用 webpack 打包生成服務器端和客戶端的代碼。
13.1.2.?運行階段
1. 服務器渲染:接收請求,執行對應的頁面組件,生成 HTML。
2. 客戶端激活:在瀏覽器端,React 接管頁面,激活組件的交互功能。
13.2.?服務端渲染流程詳解
1. 請求接收:服務器接收到客戶端請求。
2. 路由匹配:根據請求的 URL,匹配對應的頁面組件。
3. 數據預取:
-
執行頁面組件的 getServerSideProps 或 getStaticProps 方法,獲取數據。
-
數據獲取可以是異步的,如調用 API 接口。
4. 渲染頁面:
-
將組件渲染為 HTML 字符串。
-
包含初始的狀態數據。
5. 響應返回:將生成的 HTML 返回給客戶端。
13.3.?客戶端激活過程(Hydration)
1. 客戶端接收到 HTML 后,加載 JavaScript 文件。
2. React 接管頁面,將靜態的 HTML 轉換為可交互的 DOM。
3. 對比服務器端和客戶端的虛擬 DOM,確保一致性。
13.4.?熱重載與開發體驗
1. 熱重載(HMR):
-
在開發環境中,修改代碼后,頁面自動更新,無需手動刷新。
-
提高開發效率。
2. 錯誤處理:
-
友好的錯誤提示,便于調試和定位問題。
-
顯示詳細的錯誤堆棧信息。
14.?參考資料
-
nextjs: Next.js by Vercel - The React Framework
-
waku, 輕量級 react ssr: Waku, the minimal React framework
-
rsc: Server Components – React
-
renderToString: renderToString – React
-
next compiler: Architecture: Next.js Compiler | Next.js
-
prerender: https://github.com/prerender/prerender