跳转到主要内容
返回文章列表
已发布 - 内容完整

Next.js 14 新特性实战体验:App Router 到底好不好用

前端开发阅读时间:14 分钟
#Next.js#React#App Router#实战经验

迁移背景:为什么从Pages Router转到App Router

2026年2月,我决定将Harukaze Lab个人网站从Next.js Pages Router迁移到App Router。这不是一次简单的框架升级,而是开发思维的根本性转变

迁移前的痛点:

  • LCP 4.2秒(首屏加载太慢)
  • Bundle Size 245KB(客户端JS太大)
  • Lighthouse评分只有62(不及格)

核心变化:Server Components默认模式

最大的改变:所有组件默认都是Server Components,只有明确标记"use client"的才是Client Components。

数据获取方式的革命

// ❌ 旧方式(Pages Router + useEffect)
function ArticleList() {
  const [articles, setArticles] = useState([])
  
  useEffect(() => {
    fetch('/api/articles')
      .then(res => res.json())
      .then(data => setArticles(data))
  }, [])
  
  return articles.map(article => )
}

// ✅ 新方式(App Router + Server Component)
async function ArticleList() {
  const articles = await db.query('SELECT * FROM articles')
  
  return articles.map(article => )
}

效果:代码量减少40%,客户端JS减少62%。

性能优化成果

指标优化前优化后提升幅度
LCP(首屏内容绘制)4.2s1.1s⬆️ 74%
Bundle Size245KB87KB⬇️ 64%
Lighthouse评分6295⬆️ 53%
FID(首次输入延迟)180ms45ms⬆️ 75%

具体优化技术

1)图片优化 next/image

  • WebP自动转换+懒加载+Blur placeholder
  • 体积减少60%

2)代码分割 React.lazy()

  • 动态导入非首屏组件
  • @next/bundle-analyzer分析大文件

3)缓存策略 ISR + SWR

export const revalidate = 60 // ISR:每60秒增量静态再生成

4)CSS优化 Tailwind PurgeCSS

  • 移除80%未使用样式
  • Critical CSS内联

App Router最佳实践

Server Components用于:

  • ✅ 数据获取和数据库查询
  • ✅ 访问后端资源和敏感信息
  • ✅ 直接操作文件系统
  • ✅ 减少客户端JavaScript

Client Components仅在需要时使用:

  • ❗ useState / useEffect等React Hooks
  • ❗ 浏览器事件处理(onClick/onChange)
  • ❗ 浏览器API(localStorage/geolocation)
  • ❗ 需要实时交互的UI组件

常见坑及解决方案

坑1:过度使用"use client"

症状:几乎所有组件都加了"use client",性能没有改善甚至下降。

解决方案:默认Server Components,只在真正需要时添加"use client"。

坑2:Client Components中fetch数据

症状:出现Waterfall请求(串行请求导致加载慢)。

解决方案:数据获取提升到Server Components或使用Server Actions。

坑3:第三方脚本阻塞渲染

症状:LCP和FID指标变差。

解决方案

import Script from 'next/script'

<Script
  src="https://example.com/third-party.js"
  strategy="lazyOnload"
  onLoad={() => console.log('Script loaded')}
/>

Server Actions实战

替代传统API路由的新方式:

// app/actions.ts
'use server'

import { z } from 'zod'
import { revalidatePath } from 'next/cache'

const contactSchema = z.object({
  name: z.string().min(2),
  email: z.string().email(),
  message: z.string().min(10)
})

export async function submitContact(formData: FormData) {
  const validated = contactSchema.parse({
    name: formData.get('name'),
    email: formData.get('email'),
    message: formData.get('message')
  })
  
  await db.contacts.create({ data: validated })
  revalidatePath('/contact') // 自动刷新缓存
  
  return { success: true }
}

Streaming SSR + Suspense实践

import { Suspense } from 'react'

function LoadingSkeleton() {
  return <div className="animate-pulse">Loading...</div>
}

export default function Page() {
  return (
    <div>
      <Suspense fallback={<LoadingSkeleton />}>
        <SlowComponent /> // 这个组件会流式加载
      </Suspense>
      
      <FastComponent /> // 这个组件立即显示
    </div>
  )
}

效果:TTV(Time To View)降低40%,用户体验显著提升。

监控体系

  • Vercel Analytics:实时性能监控和用户行为分析
  • Sentry错误追踪:捕获并追踪生产环境错误
  • Lighthouse CI:每次部署自动运行性能测试

本文基于作者2026年2-3月的真实项目迁移经验整理。最后更新于2026年3月25日。

最后更新:2026-03-25
讨论这篇文章

这篇文章对你有帮助吗?