从0死磕全栈之Next.js 流式渲染(Streaming)实战:实现渐进式加载页面,提升用户体验

你是否遇到过页面"白屏几秒才出内容"的问题?Next.js 的 流式渲染(Streaming) 功能,可以让你的页面像视频一样"边加载边显示",用户无需等待全部数据就看到部分内容。本文通过一个简单例子,手把手教你用 App Router 实现渐进式加载。


一、什么是流式渲染(Streaming)?

在传统 SSR(服务端渲染)中,服务器必须等所有数据加载完,才能返回完整 HTML 给浏览器。用户看到的是"白屏 → 突然全屏内容"。

流式渲染 允许服务器分块发送 HTML

  • 先返回页面骨架(如导航栏、标题)
  • 再逐步填充数据区域(如文章内容、评论)

✅ 用户感知更快,SEO 友好,体验更流畅。

💡 Next.js App Router 原生支持流式渲染,配合 React 18 的 Suspense,开箱即用!


二、核心原理:Suspense + 异步组件

Next.js 利用 React 18 的 <Suspense> 组件,将页面拆分为多个"可延迟加载"的区块。

结构如下:

jsx 复制代码
<Suspense fallback="加载中...">
  <AsyncComponent /> {/* 这个组件内部可以 await 数据 */}
</Suspense>

AsyncComponent 还在 fetch 数据时,先显示 fallback;数据回来后,自动替换为真实内容。


三、实战例子:新闻详情页的渐进式加载

我们模拟一个新闻页面,包含:

  • 固定头部(立即显示)
  • 新闻标题(快速显示)
  • 新闻正文(较慢,模拟延迟)
  • 评论区(最慢,模拟复杂查询)

目标:让用户先看到标题,再看到正文,最后看到评论,而不是干等 3 秒。


第一步:创建 Next.js 项目(使用 App Router)

bash 复制代码
npx create-next-app@latest streaming-demo
# 选择:Yes (使用 App Router)
cd streaming-demo

第二步:创建新闻详情页

创建文件:app/news/[id]/page.js

jsx 复制代码
// app/news/[id]/page.js
import { Suspense } from 'react';
import NewsTitle from './NewsTitle';
import NewsContent from './NewsContent';
import Comments from './Comments';

export default function NewsPage({ params }) {
  const { id } = params;

  return (
    <div style={{ padding: '2rem', fontFamily: 'sans-serif' }}>
      <header style={{ marginBottom: '2rem' }}>
        <h1>📰 新闻中心</h1>
      </header>

      {/* 标题:快速加载,不包裹 Suspense */}
      <NewsTitle id={id} />

      {/* 正文:中等延迟,用 Suspense */}
      <Suspense fallback={<p>正在加载新闻内容...</p>}>
        <NewsContent id={id} />
      </Suspense>

      {/* 评论区:高延迟,用 Suspense */}
      <div style={{ marginTop: '2rem', borderTop: '1px solid #eee', paddingTop: '1rem' }}>
        <h2>💬 评论区</h2>
        <Suspense fallback={<p>正在加载评论,请稍候...</p>}>
          <Comments id={id} />
        </Suspense>
      </div>
    </div>
  );
}

第三步:创建异步组件(模拟延迟)

1. 新闻标题(快速,0.5秒)

jsx 复制代码
// app/news/[id]/NewsTitle.js
export default async function NewsTitle({ id }) {
  // 模拟快速 API 调用
  await new Promise(resolve => setTimeout(resolve, 500));
  return <h2>【快讯】第 {id} 号新闻标题</h2>;
}

2. 新闻正文(中等,1.5秒)

jsx 复制代码
// app/news/[id]/NewsContent.js
export default async function NewsContent({ id }) {
  // 模拟较慢的数据获取
  await new Promise(resolve => setTimeout(resolve, 1500));
  return (
    <div>
      <p>这是第 {id} 号新闻的详细内容...</p>
      <p>数据加载较慢,但用户已看到标题,不会觉得卡顿。</p>
    </div>
  );
}

3. 评论区(慢,2.5秒)

jsx 复制代码
// app/news/[id]/Comments.js
export default async function Comments({ id }) {
  // 模拟复杂查询(如数据库 JOIN)
  await new Promise(resolve => setTimeout(resolve, 2500));
  return (
    <ul>
      <li>用户A:内容很棒!</li>
      <li>用户B:期待更多更新。</li>
      <li>用户C:加载虽然慢,但体验不差 👍</li>
    </ul>
  );
}

第四步:添加全局布局(可选)

创建 app/layout.js 让页面更完整:

jsx 复制代码
// app/layout.js
export default function RootLayout({ children }) {
  return (
    <html lang="zh">
      <body>
        {children}
      </body>
    </html>
  );
}

第五步:运行并观察效果

bash 复制代码
npm run dev

访问 http://localhost:3000/news/123

你会看到:

  1. 立即显示"新闻中心"和页面结构
  2. 约 0.5 秒后显示新闻标题
  3. 约 1.5 秒后显示新闻正文
  4. 约 2.5 秒后显示评论区

🔍 打开浏览器开发者工具 → Network → 看 HTML 响应,会发现内容是分块传输的(Chunked Transfer)!


四、流式渲染的优势总结

优势 说明
更快的首屏感知 用户无需等待全部数据
更好的 SEO 搜索引擎能更快抓取关键内容
降低跳出率 用户看到内容后更愿意等待剩余部分
天然支持 Suspense 无需复杂状态管理

五、注意事项

  1. 仅 App Router 支持:Pages Router 不支持流式渲染。
  2. 服务端组件默认 :上述组件都是服务端组件(无需 'use client')。
  3. 避免过度拆分 :不是每个组件都需要 Suspense,只对慢速、非关键内容使用。
  4. fallback 要轻量fallback 内容应简单(如文字、骨架屏),避免复杂逻辑。

六、进阶:配合 loading.js

Next.js 还支持页面级 loading(如路由切换时):

jsx 复制代码
// app/news/[id]/loading.js
export default function Loading() {
  return <p>正在加载新闻页面...</p>;
}

但注意:loading.js 是页面级 loading,而 Suspense 是组件级流式加载,两者互补。


七、结语

流式渲染是现代 Web 应用提升用户体验的利器。Next.js 通过 App Router + React Suspense,让这一高级功能变得简单、直观、开箱即用

通过本文的新闻页面例子,你已经掌握了:

  • 如何用 Suspense 包裹慢速组件
  • 如何模拟异步数据延迟
  • 如何实现内容的渐进式展示

现在,就去优化你的 Next.js 项目吧!让用户告别"白屏等待" 🚀

流式渲染不是炫技,而是以用户为中心的加载哲学------让用户先看见,再等待,始终掌控体验节奏。


相关推荐
web打印社区3 小时前
使用React如何静默打印页面:完整的前端打印解决方案
前端·javascript·vue.js·react.js·pdf·1024程序员节
喜欢踢足球的老罗3 小时前
[特殊字符] PM2 入门实战:从 0 到线上托管 React SPA
前端·react.js·前端框架
小光学长3 小时前
基于Vue的课程达成度分析系统t84pzgwk(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
前端·数据库·vue.js
Baklib梅梅4 小时前
探码科技再获“专精特新”认定:Baklib引领AI内容管理新方向
前端·ruby on rails·前端框架·ruby
南方以南_4 小时前
Chrome开发者工具
前端·chrome
YiHanXii5 小时前
this 输出题
前端·javascript·1024程序员节
楊无好5 小时前
React中ref
前端·react.js
程琬清君5 小时前
vue3 confirm倒计时
前端·1024程序员节
歪歪1005 小时前
在C#中详细介绍一下Visual Studio中如何使用数据可视化工具
开发语言·前端·c#·visual studio code·visual studio·1024程序员节
唔665 小时前
flutter实现web端实现效果
前端·flutter