跳至主要内容
Rosecraft Studios

使用 Next.js 15 构建现代网站应用

理解 Next.js 15 的 App Router、React Server Components,以及它们如何改变应用的渲染和数据流。

Corey Rosamond · 2026/3/1 · 约 4 分钟阅读

本文为英文原文的简体中文译文。资料和事件日期保留原文发表时的语境;代码示例保持原样。 Read in English

使用 Next.js 15 构建现代网站应用

使用 App Router

网站开发方式已经发生很大变化。Next.js 15 的 App Router 与 React Server Components 不只是小幅改进,也改变了构建应用时对服务器与浏览器职责的理解。

本站使用 Next.js 15 App Router。以下示例用于解释渲染模型,并非性能基准,也不保证更换路由器就能改善所有应用。

React Server Components:核心变化

React Server Components(RSC)让组件完全在服务器上渲染,其自身的 JavaScript 不发送到客户端。这与传统 SSR 有区别。

// This component runs on the server. Interactive descendants may still need client JavaScript.
export async function RecentProjects() {
  const projects = await db.project.findMany({
    where: { published: true },
    orderBy: { createdAt: 'desc' },
    take: 6,
  });

  return (
    <section>
      {projects.map((project) => (
        <ProjectCard key={project.id} project={project} />
      ))}
    </section>
  );
}

关键是:在消费数据的位置获取数据。不必再从 getServerSideProps 层层传递属性,也能减少为服务端数据设置全局状态的需要。

默认使用 Server Components。需要浏览器 API、状态或事件处理器时再加入 "use client"。应用中的大量内容可以继续在服务端渲染。

App Router 架构

App Router 采用基于文件系统的路由和一组约定。

布局与模板

布局在导航之间保留,保存状态并减少不必要的重新渲染。模板在导航时重新挂载,适合进入动画等场景。

src/app/
├── layout.tsx        # Root layout (shared header, footer)
├── template.tsx      # Page transition wrapper
├── page.tsx          # Homepage
├── blog/
│   ├── layout.tsx    # Blog-specific layout (sidebar TOC)
│   ├── page.tsx      # Blog index
│   └── [slug]/
│       └── page.tsx  # Individual blog posts

动态数据与静态生成

generateStaticParams 提供构建时生成页面所需的动态路由参数;实际行为仍取决于该路由的渲染和缓存选择。generateMetadata 提供逐页元数据:

export async function generateStaticParams() {
  const posts = getAllPosts();
  return posts.map((post) => ({ slug: post.slug }));
}

export async function generateMetadata({ params }: Props): Promise<Metadata> {
  const { slug } = await params;
  const post = getPostBySlug(slug);
  if (!post) return {};

  return {
    title: post.frontmatter.title,
    description: post.frontmatter.description,
  };
}

测量您正在改变的边界

在服务端与客户端之间移动功能之前,记录 JavaScript 体积、请求顺序、渲染时间和交互行为。变更后重复相同流程。将依赖移出客户端依赖图可能减少下载,但缓慢数据库查询或未缓存的服务端工作仍可能拖慢页面。

Next.js 15 组件文档解释了不同组件在哪里运行,以及初始页面如何变得可交互。

流式渲染与 Suspense

Next.js 15 使用 React Suspense 向浏览器流式发送 HTML,让较慢组件不必阻塞整个页面:

import { Suspense } from 'react';

export default function DashboardPage() {
  return (
    <div>
      <h1>Dashboard</h1>
      <Suspense fallback={<MetricsSkeleton />}>
        <AnalyticsMetrics />
      </Suspense>
      <Suspense fallback={<ActivitySkeleton />}>
        <RecentActivity />
      </Suspense>
    </div>
  );
}

Suspense 允许已经准备好的部分先显示,较慢区域随后完成。时间仍取决于边界之前的工作、服务器与网络。选择有用的占位内容,并在真实延迟条件下测试加载体验。

Server Actions:通过服务端函数修改数据

Server Actions 让表单处理可以由一个在服务器运行的函数完成:

'use server';

export async function submitContactForm(formData: FormData) {
  // Import the same schema used by the form; do not trust type assertions.
  const { name, email, message } = contactSchema.parse({
    name: formData.get('name'),
    email: formData.get('email'),
    message: formData.get('message'),
  });
  // Apply authorization and abuse controls appropriate to the operation.

  await db.contactSubmission.create({
    data: { name, email, message },
  });

  await sendNotificationEmail({ name, email, message });
  revalidatePath('/admin/submissions');
}

在 Server Components 中使用 Server Actions 的表单支持渐进增强。必须验证输入,并分别处理数据修改与通知失败,避免重试导致重复保存。

选择适合的方式

用渲染模型简化具体数据流或交互。保持客户端边界精简,设计加载和错误状态,并使用接近生产的数据验证结果。新部署应检查仍受支持的版本及安全更新,不要只凭文章标题选版本。

准备改进现有网站应用?联系我们,讨论合适的 Next.js 架构如何改善产品性能与使用体验。

作者:Corey Rosamond,Rosecraft 创始人兼首席工程师

继续阅读

订阅工作室邮件

留下邮箱以接收工作室更新。订阅后请检查确认邮件;确认邮件目前使用英文。

了解隐私政策

下一步,从交流开始

把您的问题,变成清晰的下一步。

告诉我们您想开发或改进什么。我们会一起梳理范围、限制和合适的工程方案。

聊聊项目