如何让你的 Next.js 应用秒开?预渲染机制是关键!本文将带你彻底搞懂两种预渲染方式的区别和实战应用。
前言:为什么需要预渲染?
大家好,我是前端大鱼。最近在自己的项目中深度使用了 Next.js,不得不说它的预渲染能力真的太香了!
想象一下这样的场景:用户打开你的网站,几乎瞬间看到完整内容,而不是先看一个 loading 动画等待几秒钟。这就是预渲染带来的魔力!
与传统 React SPA 相比,Next.js 的预渲染让 SEO 再也不是问题,搜索引擎爬虫可以直接看到完整的页面内容。今天我就带大家彻底搞懂 Next.js 的预渲染机制。
一、预渲染的两种方式
1.1 静态生成(SSG)- 推荐首选
构建时生成页面,直接输出 HTML 文件扔到 CDN 上。
jsx
export default function HomePage({ posts }) {
return (
<div>
<h1>博客首页</h1>
{posts.map(post => (
<Article key={post.id} post={post} />
))}
</div>
);
}
export async function getStaticProps() {
const res = await fetch('https://api.example.com/posts');
const posts = await res.json();
return {
props: { posts }, // 传递给页面组件
revalidate: 60, // 60秒后可重新生成(ISR)
};
}
优点:
- ⚡️ 速度极致:CDN 直接返回静态文件,快就一个字
- 💰 成本极低:不需要服务器实时计算
- 🔍 SEO 友好:内容完整可抓取
- 🚀 高并发:轻松应对流量高峰
适用场景:
- 博客、文档站
- 电商商品列表页
- 公司官网
- 营销落地页
1.2 服务器端渲染(SSR)- 按需使用
每次请求时生成页面,适合个性化内容。
jsx
export default function UserProfile({ user }) {
return (
<div>
<h1>欢迎, {user.name}!</h1>
<p>这是你的个人主页</p>
</div>
);
}
// 每次请求都运行
export async function getServerSideProps(context) {
// 获取 cookies 验证用户
const token = context.req.cookies.auth;
const user = await fetchUser(token);
if (!user) {
return {
redirect: {
destination: '/login', // 未登录跳转
permanent: false,
},
};
}
return {
props: { user }, // 传递给页面
};
}
优点:
- 📊 数据实时:每次都是最新数据
- 👤 个性化:基于用户请求定制内容
- 🔐 安全性:敏感数据处理在服务端
适用场景:
- 用户仪表盘
- 实时数据页面
- 需要权限验证的页面
二、动态路由的预渲染技巧
对于动态路由(如 /posts/[id].js
),需要 getStaticPaths
配合:
jsx
// pages/posts/[id].js
export default function PostDetail({ post }) {
return <Article content={post.content} />;
}
// 告诉 Next.js 哪些路径需要预渲染
export async function getStaticPaths() {
const posts = await fetch('https://api.example.com/posts');
const paths = posts.map(post => ({
params: { id: post.id.toString() },
}));
return {
paths,
fallback: 'blocking', // 重要参数!
};
}
// 获取具体数据
export async function getStaticProps({ params }) {
const post = await fetchPost(params.id);
return {
props: { post },
revalidate: 3600, // 每小时更新一次
};
}
fallback 参数详解:
false
:只渲染指定路径,其他 404true
:先返回降级页面,后台生成新页面'blocking'
:等待生成完成再返回,用户体验更好
三、实战选择指南
3.1 如何选择?
根据你的业务场景来定:
用 SSG(静态生成)如果:
- 内容不经常变化
- 需要极致的性能
- 页面是公开的,不需要用户验证
用 SSR(服务器端渲染)如果:
- 数据实时性要求高
- 内容高度个性化
- 需要访问请求上下文(如 cookies)
3.2 性能对比
指标 | SSG | SSR |
---|---|---|
加载速度 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
SEO 支持 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
实时性 | ⭐⭐(可配 ISR) | ⭐⭐⭐⭐⭐ |
服务器压力 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
开发复杂度 | ⭐⭐⭐ | ⭐⭐⭐⭐ |
3.3 混合使用案例
在实际项目中,我们通常混合使用:
jsx
// 主页:SSG + 客户端数据获取
export default function Home({ initialData }) {
const [realTimeData, setRealTimeData] = useState(null);
// 静态部分优先展示
// 动态部分客户端获取
useEffect(() => {
fetchRealTimeData().then(setRealTimeData);
}, []);
return (
<div>
<StaticContent data={initialData} />
{realTimeData && <DynamicContent data={realTimeData} />}
</div>
);
}
export async function getStaticProps() {
const initialData = await fetchInitialData();
return { props: { initialData }, revalidate: 60 };
}
四、最佳实践与坑点避雷
4.1 一定要知道的坑
坑1:getStaticPaths 的 fallback 选择
jsx
// 错误:大量动态页面时用 false
return { paths: [], fallback: false };
// 正确:用 blocking 或 true
return { paths: [], fallback: 'blocking' };
坑2:API 路由不匹配
jsx
// 错误:在 getStaticProps 里调用了内部 API
const res = await fetch('http://localhost:3000/api/posts');
// 正确:直接导入函数或调用外部 API
const posts = await getPostsFromDB();
4.2 性能优化技巧
1. 使用 ISR(增量静态再生)
jsx
export async function getStaticProps() {
return {
props: { /* ... */ },
revalidate: 60, // 60秒后可重新生成
};
}
2. 优化图片加载
jsx
import Image from 'next/image';
export default function Product({ product }) {
return (
<div>
<Image
src={product.image}
alt={product.name}
width={500}
height={300}
placeholder="blur" // 占位优化
/>
</div>
);
}
3. 代码分割自动完成 Next.js 自动按页面做代码分割,无需额外配置!
五、总结
Next.js 的预渲染机制是其最大亮点之一,正确使用能让你的应用性能飞起:
- SSG 用于静态内容 - 极致性能,CDN 友好
- SSR 用于动态内容 - 实时数据,个性化强
- 混合使用更灵活 - 根据不同场景选择方案
- ISR 平衡两者 - 静态生成 + 定时更新
掌握了这些,你就能充分发挥 Next.js 的优势,打造出高性能的 React 应用!
互动时间:大家在用 Next.js 时遇到过哪些预渲染的问题?欢迎在评论区分享你的经验和疑问!
关注公众号" 大前端历险记",掌握更多前端开发干货姿势!