⚡️ 聊一聊Nextjs的渲染策略,以及如何选择合适的渲染策略

news2024/9/9 0:06:45

渲染策略分类

SSR:Server-Side Rendering,服务器端渲染;

SSG :Server-Static Generation,服务端静态生成,也叫编译生成

ISR :Incremental Static Regeneration 静态增量生成

CSR:Client-Side Rendering,客户端渲染

默认情况,Next.js 会预渲染每个页面。这意味着 Next.js 会将网站的所有页面提前生成静态 HTML 文件并保存下来。当用户访问网站时,服务器会返回预渲染好的静态 HTML 文件,而不是使用 JavaScript 动态生成网页内容。
在直接使用 Vue 或者 React 时,页面的渲染是完全由 JS 执行的,在 JS 未渲染完成前,页面中可能只有类似 <div id='root'></div> 的一个容器标签,当 JavaScript 文件被加载并执行时,它们会根据代码逻辑和数据来生成最终的 HTML 标记和页面内容,并将其插入到页面中的容器标签中。

在 Next.js 中想要使用某种渲染方式,例如我想指定 SSR 或是 SSG,并不是说直接在某个配置文件中改一个配置就可以的,而是我们在页面中使用了一些相关的 API,而 Next.js 在打包时检测到了才会进行相应的页面构建策略。

渲染效果对比

在 Next.js 中,预渲染(Pre-rendering)和非预渲染(Non-pre-rendering)是两种不同的页面渲染方式

  1. 预渲染是指在构建时或请求时生成 HTML 页面,并在客户端请求时直接返回生成的 HTML。预渲染可以提高页面加载速度和 SEO 性能。即SSG、SSR。

  2. 非预渲染是指在客户端渲染页面内容。这意味着 HTML 页面在客户端生成,而不是在构建时或请求时生成。适用于需要在客户端动态生成内容的页面。即CSR。

静态网站生成(SSG)

Next’s 中静态网站生成一般分为三种情况,分别是

  1. 纯静态页面,不需要依赖外部数据
  2. 页面的 内容 依赖外部数据
  3. 页面的 路径 依赖外部数据
不需要依赖外部数据
function About() {
  return <div>About</div>
}export default About

这种情况最简单,Next.js 会在打包时直接生成一个静态的 HTML。

页面的内容依赖外部数据
export default function Blog({ posts }) {
  // 渲染文章...
}// 这个函数会在 build 时接收请求
export async function getStaticProps() {
  // 请求 API 获取文章数据
  const res = await fetch('https://.../posts')
  const posts = await res.json()// 在构建时,Blog 组件可以接收到 posts 这个 props
  return {
    props: {
      posts,
    },
  }
}

为了能够在预渲染的时候拿到外部的数据,可以在定义组件的那个文件中暴露一个异步函数 getStaticProps ,在打包页面时 Next.js 会先执行 getStaticProps 中的操作,例如发送请求,数据处理之类的。

然后可以返回一个对象,其中 props 字段的值会在渲染组件时作为 props 传入,这样就实现了构建时从外部获取数据。

页面的路径依赖外部数据

Next.js 的路由是由文件系统驱动的,每个页面都对应着一个文件,这个文件的路径就是这个页面的路由路径。例如,pages/index.js 对应着根路径 /,而 pages/about.js 对应着 /about 路径。

当然不是所有的页面都是固定路由的,而动态路由就是一种可以基于 URL 参数动态生成页面的路由。例如,你可以创建一个 /posts/[id] 的页面路由,用于显示具有不同 id 值的文章详情页面。

而如果我们使用了动态路由,例如前面提到的文章 id ,那么 Next.js 如何得到我们有哪些文章 id 以实现预渲染呢?

// 这个函数在 build 时会调用
export async function getStaticPaths() {
  // 请求 API 获取数据
  const res = await fetch('https://.../posts')
  const posts = await res.json()// 基于 posts 获取我们想要预渲染的路径
  const paths = posts.map((post) => ({
    params: { id: post.id },
  }))// 在 build 时我们只会预渲染 paths 数组中的路径
  // { fallback: false } 意为其他的路由都会返回 404
  return { paths, fallback: false }
}

可以在定义组件的那个文件中再暴露一个异步函数 getStaticPaths ,这个函数可以返回一个包含 pathsfallback 属性的对象,paths 是一个包含了所有动态路由路径的数组,它决定了哪些路径将被预渲染。而 fallback 则表示访问还没有生成 html 的路径时,要采取怎么样的策略,它存在三种情况

  • false:访问任何在 getStaticPaths() 函数中未返回的路径都会响应 404 页面。
  • true:build 时未生成的路径不会返回 404 页面。而是在第一次请求时进行 SSR 并返回生成的 HTML。这个生成的 HTML 会被缓存,也就是说你访问这个路径时,即便对应的数据已经更新了还是会返回原本的页面,直到缓存过期重新生成 HTML。
  • 'blocking''blocking' 策略与设置为 true 时相同,不同点在于设置为 true 时,我们会直接进入访问的路径,并同时执行 getStaticProps ,并且可以通过 router.isFallback 判断getStaticProps 是否已经执行完成,而 'blocking' 策略则会先执行 getStaticProps ,直到执行完成才会进入新的页面。也就是同步与异步的关系。

虽然预渲染这么方便,将我的每个页面都生成静态文件了,那如果页面更新了怎么办呢?难道我需要执行 build 重新生成所有页面嘛?这里就需要引入 ISR 的概念了。

静态增量生成(ISR)

ISR(Incremental Static Regeneration) 是一种在静态站点生成过程中,增量更新部分页面的技术。传统的静态网站生成方式需要每次完全重新生成全部页面,这在网站内容变化频繁的情况下可能会导致生成时间较长,同时也可能会降低网站的性能。

ISR 的思想是只 重新生成需要更新部分页面。这样可以显著减少生成时间和资源占用,并且能够提高网站的响应速度。当用户请求一个需要更新的页面时,ISR 会在后台自动重新生成该页面,然后将其缓存,以便下一次请求时可以快速响应。

要在 Next.js 中开启 ISR ,只需要在前面介绍的 getStaticProps 函数中返回一个 revalidate 属性,下面放一个官方的示例:

function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  )
}// 这个方法会在服务端渲染或者 build 时被调用
// 当使用了 serverless 函数、开启 revalidate 并且接受到新的请求时也会被重新调用
export async function getStaticProps() {
  const res = await fetch('https://.../posts')
  const posts = await res.json()return {
    props: {
      posts,
    },
    
    // Next 将会尝试重新生成页面:
    // - 接受到新的请求
    // - 每隔最多十秒钟
    revalidate: 10, // 单位为秒
  }
}// 这个方法会在服务端渲染或者 build 时被调用
// 当该路径还没有被生成过就会被重新调用
export async function getStaticPaths() {
  const res = await fetch('https://.../posts')
  const posts = await res.json()// 基于 posts 获取我们想要预渲染的路径
  const paths = posts.map((post) => ({
    params: { id: post.id },
  }))// 在 build 时,我们将只预渲染 paths 中的路径
  // { fallback: 'blocking' } 在页面不存在时按需进行服务端渲染。
  return { paths, fallback: 'blocking' }
}export default Blog

ISR 的实现方式是将某些页面标记为可 ISR 页面。这些页面在生成时与 SSG 页面相同,但它们还有一个“revalidate”(再生成时间) 。这个时间告诉 Next.js 何时需要重新生成页面。

例如,假设我们需要构建一个新闻网站,希望能在首页上显示最新的新闻文章。在 Next.js 中,我们就可以将首页标记为 ISR 页面,并设置重新生成时间为 10 秒钟。这意味着,Next.js 将在访问首页时,返回上一次生成的静态页面,同时在后台开始重新生成新的页面。10 秒后,当新页面生成完毕后,Next.js 会将新页面替换旧页面,并提供给用户。

服务端渲染 (SSR)

在 Next.js 中,如果启用了 SSR,那么每次的每次请求都会重新生成页面。想要开启 SSR,我们可以在定义组件的那个文件中暴露一个异步函数 getServerSideProps,这个方法类似于 getStaticProps ,只是执行的时机不同, getServerSideProps 会在每次页面接受请求时都调用。

export default function Page({ data }) {
  // 渲染数据...
}// 这个方法每次请求时都会调用
export async function getServerSideProps() {
  // 从外部 API 获取数据
  const res = await fetch(`https://.../data`)
  const data = await res.json()// 通过 props 向组件内传入数据
  return { props: { data } }
}

除了调用时机外,getServerSidePropsgetStaticProps 并无二致。

客户端渲染 (CSR)

可以使用 Next.js 的 客户端渲染 + next export 实现。

在 Next.js 中想要使用客户端渲染也很简单,只要上述的这些 API ,例如 getStaticPropsgetServerSideProps 都没有使用,数据都是通过在组件内部使用 axios 或者 fetch 去发送请求获取并渲染的,那么我们使用的就是纯客户端渲染了,与直接使用 Vue 或 React 并无二致。

但即便你的每一个页面都是使用的客户端渲染,在执行 build 时,Next.js 还是会为你打包成一个需要持续运行的 Node.js 服务,而不是直接打包为一个静态文件。

想要导出为静态文件,需要使用单独的打包方式,那就是静态 HTML 导出。

静态 HTML 导出

Next.js 可用于生成静态应用程序,可以实现在浏览器中使用 React 而无需 Node.js 服务器。就可以使用 next export 命令去将你的站点构建为一个静态的文件。

首先更新 next.config.js 中的 outputexport :

/**
 * @type {import('next').NextConfig}
 */
const nextConfig = {
  output: 'export',
}
​
module.exports = nextConfig

然后更新 package.jsonbuild 指令以包含 next export

"scripts": {
  "build": "next build && next export"
}

运行 npm run build 会生成一个 out 目录。

如何选择渲染方式

选择客户端渲染(CSR)的场景:
  1. 交互式用户体验:如果你的应用需要高度交互式的用户体验,比如单页应用程序(SPA)那样的即时反馈和流畅的界面切换,CSR 是一个很好的选择。它允许在不重新加载整个页面的情况下动态更新内容,提升了用户体验。
  2. 动态数据需求:当应用中的大部分内容依赖于用户操作或实时更新时(如聊天应用、仪表盘、个性化内容展示),CSR 能更高效地处理这些需求,因为它可以直接在客户端根据用户行为或API响应来更新页面。
  3. 减少服务器负担:CSR将渲染工作转移到了客户端,这意味着服务器只需提供初始的HTML文档和必要的数据API,减少了服务器的CPU和内存消耗,尤其适合流量较大的应用。
  4. 初始加载时间容忍度:如果用户群体对首次页面加载时间有较高容忍度,或者可以通过骨架屏、懒加载等技术缓解等待感,那么可以选择CSR。因为相比SSR,CSR在首次加载时可能需要更长时间来下载JavaScript bundle并执行渲染。
  5. SEO非关键或已有解决方案:如果SEO不是项目的主要关注点,或者已经有解决方案可以弥补CSR在SEO上的不足(例如使用预渲染、动态渲染服务),则可以偏向于选择CSR。
选择服务器端渲染(SSR)的场景:
  1. SEO优化:对于依赖搜索引擎流量的内容驱动型网站,如新闻门户、博客、电商产品列表等,SSR至关重要。搜索引擎爬虫通常更偏好服务器端渲染的页面,因为它们可以直接抓取到完整渲染的HTML内容,有助于提升搜索引擎排名。
  2. 首屏加载速度:在慢速网络环境下或对首屏加载时间有严格要求的应用中,SSR可以提供即时的、可交互的初始页面内容,无需等待JavaScript下载和执行,从而改善用户体验。
  3. 减少客户端负担:对于低端设备或资源受限的客户端,SSR可以减轻其计算负担,因为大部分渲染工作在服务器完成,客户端只需处理交互逻辑。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1947795.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

二维码的生成与识别(python)

二维码生成 from PIL import Image import qrcode from qrcode.image.styledpil import StyledPilImage from qrcode.image.styles.colormasks import SolidFillColorMask from qrcode.image.styles.moduledrawers import SquareModuleDrawer# 创建二维码对象 qr qrcode.QRCo…

智能编程,一触即发:使用AIGC优化CSS——提升前端开发效率与质量

文章目录 一、AIGC在CSS优化中的应用场景智能代码生成自动布局调整性能优化建议样式和色彩建议 二、使用AIGC优化CSS的具体步骤明确需求选择AIGC工具输入描述或设计稿审查和调整集成和测试 三、AIGC优化CSS的优势与挑战优势&#xff1a;挑战&#xff1a; 《CSS创意项目实践&…

vue3前端开发-小兔鲜项目-登录和非登录状态下的模板适配

vue3前端开发-小兔鲜项目-登录和非登录状态下的模板适配&#xff01;有了上次的内容铺垫&#xff0c;我们可以根据用户的token来判定&#xff0c;到底是显示什么内容了。 1&#xff1a;我们在对应的导航组件内修改完善一下内容即可。 <script setup> import { useUserSt…

ATE测试设备ATECLOUD专注于电源模块、电源芯片和射频组件测试

在追求效率与精度的时代背景下&#xff0c;电子测试测量行业迎来了ATE自动化测试设备的革新。这一设备的出现&#xff0c;不仅简化了测试流程&#xff0c;还大幅提高了测试的准确性和速度。 新ATE自动化测试设备&#xff1a;ATECLOUD测试平台 纳米软件深耕电测行业16年&#xf…

算法 day4 【双指针、快慢指针、环形链表】链表下

⚡刷题计划day4继续&#xff0c;可以点个免费的赞哦~ 下一期将会开启哈希表刷题专题&#xff0c;往期可看专栏&#xff0c;关注不迷路&#xff0c; 您的支持是我的最大动力&#x1f339;~ 目录 ⚡刷题计划day4继续&#xff0c;可以点个免费的赞哦~ 下一期将会开启哈希表刷题…

无法连接网络打印机0x00000709原因分析及多种解决方法

在日常办公和生活中&#xff0c;打印机是不可或缺的重要设备。然而&#xff0c;有时在连接打印机的过程中&#xff0c;我们可能会遇到错误代码0x00000709的提示。有更新补丁导致的、有访问共享打印机服务异常、有访问共享打印机驱动异常等问题导致的&#xff0c;针对访问共享打…

实验三 FPGA使用Verilog HDL设计加法器

实验目的 掌握使用Vivado软件进行设计、综合、仿真、布线的方法。掌握FPGA程序的下载方法。掌握使用Verilog HDL设计加法器的方法。 实验要求 采用Verilog HDL语言设计加法器&#xff0c;实现两个4位数的相加运算&#xff0c;并将结果通过LED灯或数码管显示出来。对设计进行综…

如何通过集成软件授权管理系统推动企业业务增长?

软件货币化已经成为许多企业商业成功的关键&#xff0c;随着全球数字化进程不断深入&#xff0c;其重要性也在不断增加。将许可解决方案优化集成到现有系统中&#xff0c;已成为从接收到订单到交付和激活许可的任何高效流程的基本要素。 软件货币化无处不在 无论是传统的软件企…

[言简意赅] Matlab生成FPGA端rom初始化文件.coe

&#x1f38e;Matlab生成FPGA端rom初始化文件.coe 本文主打言简意赅。 函数源码 function gencoeInitialROM(width, depth, signal, filepath)% gencoeInitialROM - 生成 Xilinx ROM 初始化格式的 COE 文件%% 输入参数:% width - ROM 数据位宽% depth - ROM 数据深度% s…

在 LCD 上显示 png 图片-I.MX6U嵌入式Linux C应用编程学习笔记基于正点原子阿尔法开发板

在 LCD 上显示 png 图片 PNG 简介 无损压缩&#xff1a;PNG 使用 LZ77 派生算法进行无损压缩&#xff0c;确保图像质量不受损&#xff0c;且压缩比高 体积小&#xff1a;通过高压缩比&#xff0c;PNG 文件体积小&#xff0c;适合网络传输 索引彩色模式&#xff1a;PNG-8 格式…

Unity UGUI 之 RectTransform

本文仅作学习笔记与交流&#xff0c;不作任何商业用途 本文包括但不限于unity官方手册&#xff0c;唐老狮&#xff0c;麦扣教程知识&#xff0c;引用会标记&#xff0c;如有不足还请斧正 Unity - Manual: Rect Transform 1.Rect Transform是什么 2.轴心与锚点的映射关系 首先…

获取后端返回的图形验证码

如果后端返回的直接就是一个图形&#xff0c;有以下几种方式展示 一、直接在img标签里面的src里面调用接口 <img :src"dialogSrc" class"photo" alt"验证码图片" click"changeDialog">let orgUrl "/api/captcha" …

论文解读:DiAD之SG网络

目录 一、SG网络功能介绍二、SG网络代码实现 一、SG网络功能介绍 DiAD论文最主要的创新点就是使用SG网络解决多类别异常检测中的语义信息丢失问题&#xff0c;那么它是怎么实现的保留原始图像语义信息的同时重建异常区域&#xff1f; 与稳定扩散去噪网络的连接&#xff1a; S…

机器学习(二十):偏差和方差问题

一、判断偏差和方差 以多项式回归为例&#xff0c;红点为训练集数据&#xff0c;绿点为交叉验证数据。 下图的模型&#xff0c;训练集误差大&#xff0c;交叉验证集误差大&#xff0c;这代表偏差很大 下图的模型&#xff0c;训练集误差小&#xff0c;交叉验证集误差小&#x…

Linux网络:传输层协议TCP(二)三次挥手四次握手详解

目录 一、TCP的连接管理机制 1.1三次握手 1.2四次挥手 二、理解 TIME_WAIT 状态 2.1解决TIME_WAIT 状态引起的 bind 失败的方法 三、理解CLOSE_WAIT状态 一、TCP的连接管理机制 在正常情况下, TCP 要经过三次握手建立连接, 四次挥手断开连接 1.1三次握手 三次握手顾名思…

vue import from

vue import from 导入文件&#xff0c;从XXXX路径&#xff1b;引入文件 import xxxx from “./minins/resize” import xxxx from “./minins/resize.js” vue.config.js 定义 : resolve(src)&#xff1b;就是指src 目录 import xxxx from “/utils/auth” im…

vue3知识

目录 基础vue开发前的准备vue项目目录结构模板语法属性绑定条件渲染列表渲染通过key管理状态事件处理事件传参事件修饰符数组变化侦测计算属性Class绑定style绑定侦听器表单输入绑定模板引用组件组成组件嵌套关系组件注册方式组件传递数据Props(父传子)组件传递多种数据类型组件…

怎么批量加密U盘?U盘批量加密的方法有哪些?

加密U盘是保护U盘数据安全的重要方法。而当需要加密的U盘数量较多时&#xff0c;我们需要批量加密U盘。那么&#xff0c;U盘怎么批量加密呢&#xff1f;下面我们就来了解一下。 U盘内存卡批量只读加密专家 U盘内存卡批量只读加密专家是一款专业的U盘加密软件&#xff0c;适用于…

什么牌子的充电宝又好又耐用?认准这几个充电宝品牌!错过就吃亏

在 2024 年&#xff0c;充电宝已然成为我们生活中不可或缺的电子配件。但面对市场上琳琅满目的充电宝产品&#xff0c;如何挑选出一款适合自己的&#xff0c;却让许多人感到困惑。充电宝要怎么挑&#xff1f;这可不是一个简单的问题。不同的使用场景、不同的设备需求&#xff0…

02 MySQL数据库管理

目录 1.数据库的结构 sql语言主要由以下几部分组成 2. 数据库与表的创建和管理 1&#xff0c;创建数据库 2&#xff0c;创建表并添加数据 3&#xff0c;添加一条数据 4&#xff0c;查询数据 5&#xff0c;更新数据 6&#xff0c;删除数据 3.用户权限管理 1.创建用户 …