跟“白屏”说拜拜:用 Next.js 把 React 搬到服务器上,Google 爬虫都要喊一声“真香”

前言:除了你,没人愿意对着空白屏幕发呆

接上回。咱们用虚拟滚动把 10 万条数据治得服服帖帖。现在你的应用在渲染出来之后,性能确实很顶。

但是,有一个更尴尬的问题摆在面前:首屏加载(First Paint)

咱们之前写的 React(CSR - 客户端渲染),工作流程是这样的:

  1. 浏览器请求页面。
  2. 服务器扔回来一个几乎是空的 HTML:<div id="root"></div>
  3. 浏览器加载那个 5MB 的 JS 包。
  4. JS 执行,去调 API,拿到数据。
  5. JS 把 DOM 算出来,塞进 root 里。

这一套下来,用户在前几秒钟看到的都是大白屏 。 更惨的是 SEO(搜索引擎优化)。Google 的爬虫虽然聪明点了,但百度的爬虫那是相当"直男"。它过来一看:"哟,这网页只有一个 div?内容是空的?垃圾!" 然后转身就走,你的网页在搜索结果里永远排在第 100 页开外。

今天,我们要来聊聊 Next.js服务端渲染 (SSR)。我们要把渲染这脏活累活从用户的浏览器挪到服务器上,让用户打开网页的一瞬间,内容就是满的。

Image of CSR vs SSR architecture diagram


观念升级:不仅是框架,是"元框架"

很多兄弟对 Next.js 有误解,觉得它就是个"带路由的 React"。 错!在 2025 年的今天,Next.js 其实是 React 的完全体

React 官方团队现在都明说了:"你要写 React,推荐直接用 Next.js。" 为什么?因为 React 只是个 UI 库(View 层),而 Next.js 帮你搞定了路由、打包、SSR、API 路由、图片优化......它是全家桶。

我们重点要说的,是它的核心大招:React Server Components (RSC)


实战演练:从 useEffect 到 async/await

在传统的 CSR 项目里,我们要获取数据,通常得写个 useEffect,还得处理 loading 状态。

❌ 传统的 CSR 写法(慢、且 SEO 为 0):

tsx 复制代码
// 客户端组件
import { useState, useEffect } from 'react';

export default function UserProfile({ id }) {
  const [user, setUser] = useState(null);

  useEffect(() => {
    // 浏览器加载完 JS 后才开始发请求
    fetch(`/api/users/${id}`).then(res => res.json()).then(setUser);
  }, [id]);

  if (!user) return <div>Loading...</div>; // 用户先看 1 秒钟这个

  return <h1>{user.name}</h1>;
}

✅ Next.js (App Router) 写法(秒开、SEO 满分):

在 Next.js 的 App Router 模式下,组件默认就是服务端组件 (Server Component) 。这意味着你可以直接在组件里写 async/await,直接连数据库!

// 复制代码
// 这代码是在服务器上跑的!浏览器连一行 JS 都收不到,只收到 HTML。
import db from '@/lib/db';

async function getUser(id) {
  // 直接查库,或者调内网 API,快得飞起
  return await db.user.findUnique({ where: { id } });
}

export default async function UserPage({ params }) {
  const user = await getUser(params.id);

  // 服务器直接把渲染好的 HTML 扔给浏览器
  // 爬虫看到的就是:<h1>Jack</h1>
  return (
    <main>
      <h1>{user.name}</h1>
      <p>{user.bio}</p>
    </main>
  );
}

发生了什么?

  1. 用户请求 /user/1
  2. Next.js 服务器接收请求,执行 getUser,拿到数据。
  3. Next.js 生成完整的 HTML:<main><h1>Jack</h1>...</main>
  4. 浏览器收到 HTML,直接显示内容

没有 Loading 转圈,没有白屏。爬虫一看:"哇,内容好丰富!" 排名蹭蹭往上涨。


进阶技巧:静态生成 (SSG) ------ 也就是"作弊"

对于"用户个人主页"这种数据会变的页面,我们用 SSR(每次请求都跑一遍服务器)。 但对于"关于我们"、"博客文章"这种一万年不改一次的页面,如果每次有人访问都去查数据库,那就太冤大头了。

Next.js 有个无敌的功能叫 SSG (Static Site Generation)

你只需要告诉 Next.js:"这页面是静态的。" 它就会在构建打包 (Build Time) 的时候,把这个页面生成为一个 .html 文件。

当用户访问时,Nginx/Vercel 直接把这个 HTML 扔出去。这比 SSR 还要快,因为连数据库都不用查,甚至不需要服务器计算,这就是纯静态资源分发。

// 复制代码
// 告诉 Next.js 提前把哪些文章生成好 HTML
export async function generateStaticParams() {
  const posts = await getposts();
  return posts.map((post) => ({
    slug: post.slug,
  }));
}

export default async function BlogPost({ params }) {
  // ... 渲染逻辑
}

避坑指南:Hydration(注水)之痛

虽然 SSR 出来的 HTML 能立马看到,但它一开始是"死"的(没有交互)。 浏览器展示 HTML 后,会加载 JS,把 React 的事件监听器(onClick 等)挂载上去,这个过程叫 Hydration(注水)

如果你在服务端渲染的内容,和客户端注水时的内容不一致 ,React 就会报错: Text content does not match server-rendered HTML.

常见翻车现场:

export 复制代码
  // ❌ 错误!
  // 服务器时间是 UTC,客户端时间是 GMT+8
  // HTML 里是 10:00,JS 算出来是 18:00,直接报错
  return <div>Current time: {new Date().toLocaleTimeString()}</div>;
}

解决办法: 凡是涉及到浏览器特有属性(windowlocalStorage、时区)的,必须放到 useEffect 里,或者用 dynamic import 强制转为客户端组件。

'use 复制代码

总结:该不该上 Next.js?

如果你的项目是:

  • 后台管理系统(Dashboard) :无所谓,CSR 就够了,没人靠 SEO 搜后台。
  • 企业官网 / 博客 / 电商 / 资讯站必须上 Next.js。不上就是跟钱过不去,跟流量过不去。

SSR 解决了首屏速度,SSG 解决了高并发压力,Server Components 让前端能直接操作后端逻辑。 这就叫降维打击。

好了,我要去把那个还是 create-react-app 的老官网迁移到 Next.js 了,为了那该死的 Google 排名。


下期预告 :既然我们都已经能在 Server Components 里直接读数据库了,那是不是连 API 接口都不用写了? 没错!写 axios.post 已经是过去式了。 下一篇,我们来聊聊 "Server Actions:全栈 React 的最后一公里" 。教你如何在按钮的 onClick 里直接调用服务器函数,把"前后端分离"重新"合二为一"。

相关推荐
xiaofeichaichai4 小时前
Webpack
前端·webpack·node.js
Thecozzy4 小时前
线上 Bug 排查与修复实录
架构
鹏大师运维4 小时前
为什么信创电脑装软件总提示“软件包架构不匹配”?
linux·运维·架构·国产化·麒麟·deb·统信uos
问心无愧05134 小时前
ctf show web入门111
android·前端·笔记
唐某人丶4 小时前
模型越来越强,我们还需要 Agent 工程吗?—— 从价值重估到 Harness 实践
前端·agent·ai编程
智码看视界4 小时前
现代Web开发基础:全栈工程师的起航点
前端·后端·c5全栈
JS菌4 小时前
手写一个 AI Agent 全栈项目:从沙箱执行到子智能体的完整实现
前端·人工智能·后端
excel6 小时前
HLS TS 文件损坏的元凶:Git 提交与拉取
前端
Aphasia3116 小时前
https连接传输流程
前端·面试