React 设计模式 0x5:服务端渲染 SSR

学习如何轻松构建可伸缩的 React 应用程序:服务端渲染 SSR

# 什么是 SSR

SSR(Server-Side Rendering,服务器端渲染)是指将 React、Vue、Angular 等客户端渲染的应用在服务器端执行一次,然后将渲染结果返回给浏览器进行展示的过程。相对于客户端渲染(CSR,Client-Side Rendering),SSR 可以提高页面的首屏加载速度和搜索引擎优化(SEO),因为它可以在服务器端直接生成 HTML,并将静态资源(如 CSS、JavaScript 等)和页面数据一起返回给客户端,从而减少客户端的渲染工作量。

# 为什么使用 SSR

并不是每个应用程序都需要使用服务器端渲染。以下是选择 SSR 的一些原因:

  • 更好的用户体验
  • 快速的功能开发
  • 性能

# Next.js 优缺点

# 优点

  • 良好的 SEO:
    • 搜索引擎优化(SEO)帮助您增加网站的访问量,而 Next.js 具有内置的功能来实现这一点
  • 强大的社区支持
    • Next.js 有一个非常庞大的社区,因为这个框架仍在不断发展,日益受欢迎
  • 快速刷新
    • 在 Nex.js 应用程序上进行代码更改时,更改会在几秒钟内在浏览器上反映出来
  • 快速显示
    • Next.js 非常快,因为大多数页面都是在服务器端预渲染并在客户端上提供的
  • 图片优化
    • 自动优化图像,现在支持 AVIF 图像,使图像比 WebP 小 20%
  • TypeScript 支持
    • 自动配置和编译 TypeScript
  • 零配置
  • 优秀的开发者体验
    • 使用 NextJS,我们花更多的时间编写功能,而不是在构建工具和 Webpack 上挣扎
  • 自动路由
    • NextJS 将项目结构化为页面,并添加路由
  • 数据获取
    • 根据应用程序的用例以不同的方式呈现内容
    • 包括使用服务器端呈现或静态站点生成进行预渲染以及使用增量静态再生在运行时更新或创建内容
  • 中间件
    • 此功能使您可以在请求完成之前运行代码,以便在请求和重定向用户时更改响应到另一个路由
  • 数据安全性
    • Next.js 不会阻塞浏览器以一次性下载和执行大量的 JavaScript 代码,它有潜力显着改善总阻塞时间(TBT)等指标
    • TBT 越好,Web 应用程序就越快,对您的用户有用,这使得将他们转化为客户更有可能
    • 等待页面进行交互可能会增加跳出率
      • 这是另一个与 SEO 相关的因素
  • 性能

# 缺点

  • 研发管理
    • 如果你想使用 NextJS 构建一个在线商店,但是你没有内部的开发团队,你将需要一个专门负责开发和管理的人员
  • 路由问题
    • 由于基于文件的路由限制了 Next.js 在节点路由方面的能力,因此如果你的项目需要动态路由,你将不得不使用 Node.js 服务器
  • 没有状态管理器
    • Next.js 框架中没有内置的状态管理器
    • 为了充分利用状态管理器,你将需要另一个工具来完成它
  • 构建时间限制
    • 构建网站和应用程序的时间是受限制的
    • 对于 Next.js 而言,添加新页面到网站或应用程序不是问题,然而,对于具有许多页面的应用程序,整个网站的静态创建意味着构建时间可能会非常长

# Next.js 预渲染

Next.js 对每个页面都进行预渲染,即每个页面的 HTML 都是提前生成的,而不是由客户端完成的。

预渲染有两种类型,即:

  • 静态生成(Static Generation)
  • 服务器端渲染(Server-side Rendering)

# 静态生成

在构建时生成 HTML 页面,这些页面将在每个请求上重用。

为了生成页面,我们需要导出页面组件或 getStaticProps 函数(需要的时候,还可以导出 getStaticPaths 函数)。

# 不带数据的静态页面
代码语言:javascript
复制
const Contact = () => {
  return (
    <div>
      <h1>Contact</h1>
      <p>Send us a message!</p>
    </div>
  );
};

export default Contact;

# 带数据的静态页面

内容依赖外部数据

代码语言:javascript
复制
function UserList({ users }) {
  return (
    <ul>
      {users.map((user) => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

export async function getStaticProps() {
const res = await fetch("https://.../users");
const users = await res.json();

return {
props: {
users,
},
};
}

export default UserList;

路径依赖外部数据

  • 如,我们创建一个名为 users/[id].js.js 文件,用于根据用户的 id 显示单个用户的详细信息。我们需要从 users/[id].js 文件中导出一个名为 getStaticPaths 的异步函数
代码语言:javascript
复制
function User({ user }) {
  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.bio}</p>
    </div>
  );
}

export async function getStaticPaths() {
const res = await fetch("https://.../users");
const users = await res.json();

const paths = users.map((user) => ({
params: { id: user.id },
}));

return { paths, fallback: false };
}

export async function getStaticProps({ params }) {
const res = await fetch(https://.../users/${params.id});
const user = await res.json();

return {
props: {
user,
},
};
}

export default User;

# getServerSideProps

通过导出名为 getServerSideProps 的异步函数,可以在每个请求时生成 HTML。

代码语言:javascript
复制
function UserList({ users }) {
  return (
    <ul>
      {users.map((user) => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

export async function getServerSideProps() {
const res = await fetch("https://.../users");
const users = await res.json();

return {
props: {
users,
},
};
}

export default UserList;

# 使用 Node.js 和 Express.js 构建 SSR

使用 Node.js 和 Express.js 进行服务器端渲染是另一种从服务器端渲染 React 页面的方式。Express.js 创建路由,我们可以使用该路由基于用户的请求指定页面。

可以参考这篇文章:使用 Node.js 和 Express.js 构建 SSR (opens new window)。