文章目录

React 服务端渲染:Next.js 基础

发布于 2026-04-02 21:26:11 · 浏览 14 次 · 评论 0 条

React 服务端渲染:Next.js 基础

创建一个支持服务端渲染(SSR)的 React 应用,传统方式需要手动配置 Webpack、Babel 和 Node 服务器,过程繁琐且容易出错。Next.js 是一个基于 React 的轻量级框架,内置了 SSR、静态生成、路由系统和 API 路由等功能,能让你用最少的代码快速搭建高性能应用。


安装并启动项目

  1. 打开终端,执行以下命令创建新项目:

    npx create-next-app@latest my-ssr-app
  2. 按提示操作

    • 是否使用 TypeScript?选择 No(本指南使用 JavaScript)。
    • 是否启用 ESLint?选择 Yes
    • 是否启用 Tailwind CSS?选择 No(避免干扰核心逻辑)。
    • 是否使用 src/ 目录?选择 Yes
    • 是否使用 App Router?选择 No(本指南基于 Pages Router,更适合理解 SSR 基础)。
    • 是否自定义默认导入别名?选择 No
  3. 进入项目目录并启动开发服务器:

    cd my-ssr-app
    npm run dev
  4. 打开浏览器访问 http://localhost:3000,你会看到默认欢迎页面。


理解 Pages Router 结构

Next.js 使用文件系统作为路由。在 src/pages 目录下:

  • index.js 对应根路径 /
  • about.js 对应 /about
  • user/[id].js 对应动态路径 /user/123

删除 src/pages/index.js 中的默认内容,替换为以下最简页面:

// src/pages/index.js
export default function Home() {
  return <h1>首页</h1>;
}

实现基础服务端渲染

Next.js 提供两个关键函数用于 SSR:getServerSidePropsgetStaticProps。前者在每次请求时在服务端运行,后者在构建时运行(静态生成)。这里聚焦 getServerSideProps

  1. 修改 src/pages/index.js,添加 getServerSideProps

    // src/pages/index.js
    export default function Home({ serverTime }) {
      return (
        <div>
          <h1>首页</h1>
          <p>服务端渲染时间: {serverTime}</p>
        </div>
      );
    }
    
    export async function getServerSideProps() {
      const serverTime = new Date().toISOString();
      return {
        props: {
          serverTime,
        },
      };
    }
  2. 刷新浏览器页面,你会看到当前服务器时间。多次刷新,时间会变化,证明每次请求都触发了服务端执行。

  3. 查看页面源代码(右键 → “查看页面源代码”),你会发现 <p> 标签内已包含完整的时间字符串,而非空壳。这说明 HTML 是在服务端生成的,有利于 SEO 和首屏加载速度。


获取外部数据并渲染

真实场景中,SSR 常用于从数据库或 API 获取数据。下面模拟从外部接口获取用户信息。

  1. 创建一个模拟 API 函数(实际项目中替换为真实请求):

    // src/lib/fetchUser.js
    export async function fetchUser(userId) {
      // 模拟网络延迟
      await new Promise(resolve => setTimeout(resolve, 100));
      return {
        id: userId,
        name: `用户 ${userId}`,
           email: `user${userId}@example.com`,
      };
    }
  2. 新建页面 src/pages/user/[id].js

    // src/pages/user/[id].js
    import { fetchUser } from '../../lib/fetchUser';
    
    export default function UserPage({ user }) {
      if (!user) {
        return <p>用户不存在</p>;
      }
      return (
        <div>
          <h1>{user.name}</h1>
          <p>邮箱: {user.email}</p>
        </div>
      );
    }
    
    export async function getServerSideProps({ params }) {
      const { id } = params;
      const user = await fetchUser(id);
      return {
        props: {
          user,
        },
      };
    }
  3. 访问 http://localhost:3000/user/42,页面将显示“用户 42”的信息。URL 中的 42 通过 params.id 传入 getServerSideProps


处理错误与加载状态

getServerSideProps 在服务端运行,无法直接向用户展示“加载中”状态,但可以处理错误。

  1. 修改 fetchUser.js,使其在无效 ID 时抛出错误:

    // src/lib/fetchUser.js
    export async function fetchUser(userId) {
      await new Promise(resolve => setTimeout(resolve, 100));
      if (userId < 1) {
        throw new Error('无效用户ID');
      }
      return {
        id: userId,
        name: `用户 ${userId}`,
           email: `user${userId}@example.com`,
      };
    }
  2. 更新 getServerSideProps 以捕获错误:

    // src/pages/user/[id].js(仅修改 getServerSideProps 部分)
    export async function getServerSideProps({ params }) {
      const { id } = params;
      try {
        const user = await fetchUser(Number(id));
        return { props: { user } };
      } catch (error) {
        return { props: { user: null } };
      }
    }
  3. 访问 http://localhost:3000/user/0,页面将显示“用户不存在”。


部署到生产环境

开发完成后,需构建生产版本。

  1. 停止开发服务器(按 Ctrl + C)。

  2. 执行构建命令:

    npm run build
  3. 启动生产服务器:

    npm start
  4. 再次访问页面,行为应与开发模式一致,但性能更优。


关键函数对比表

以下表格总结 Next.js 数据获取方法的核心区别:

方法 执行时机 适用场景 是否支持动态路由参数
getServerSideProps 每次请求时 需要实时数据(如用户认证页)
getStaticProps 构建时(或 ISR) 内容变化不频繁(如博客文章)
客户端 useEffect 浏览器加载后 无需 SEO 的交互数据

选择 getServerSideProps 当你需要确保 HTML 在服务端完全生成,例如展示个性化内容或敏感信息(这些不应暴露在客户端初始 HTML 中)。


创建 _app.js 自定义全局布局(可选)

若所有页面共享相同结构(如导航栏),可创建 src/pages/_app.js

// src/pages/_app.js
export default function MyApp({ Component, pageProps }) {
  return (
    <div>
      <nav>全局导航</nav>
      <main>
        <Component {...pageProps} />
      </main>
    </div>
  );
}

此后,每个页面组件将自动包裹在此布局内,pageProps 包含从 getServerSideProps 返回的 props

评论 (0)

暂无评论,快来抢沙发吧!

扫一扫,手机查看

扫描上方二维码,在手机上查看本文