likes
comments
collection
share

Next.js14从入门到实战013:NextJS基础篇之静态和动态渲染

作者站长头像
站长
· 阅读数 4

在上一章中,您为dashboard页面获取了数据。不过,我们简要讨论了当前设置的两个局限性:

  1. 数据请求正在无意中形成瀑布效应。
  2. 仪表板是静态的,因此任何数据更新都不会反映在您的应用程序上。

在本章中,你将学习……

  1. 什么是静态渲染以及静态渲染如何提高应用程序的性能。
  2. 什么是动态渲染以及何时使用。
  3. 让仪表盘充满活力的不同方法
  4. 模拟缓慢的数据获取,看看会发生什么。

什么是静态渲染?

使用静态渲染时,数据获取和渲染会在构建时(部署时)或重新验证时在服务器上进行。然后可以在内容分发网络(CDN)中分发和缓存结果。

Next.js14从入门到实战013:NextJS基础篇之静态和动态渲染

每当用户访问您的应用程序时,缓存结果就会送达。静态呈现有几个好处:

  • 更快的网站:可对预渲染内容进行缓存和全球分发。这可确保世界各地的用户更快、更可靠地访问您的网站内容。
  • 减少服务器负载:由于内容是缓存的,因此服务器无需为每个用户请求动态生成内容。
  • 搜索引擎优化:预渲染内容更容易被搜索引擎爬虫索引,因为页面加载时内容已经可用。这可以提高搜索引擎的排名。

静态渲染适用于没有数据或用户之间共享数据的用户界面,如静态博客文章或产品页面。对于有定期更新的个性化数据的仪表盘来说,静态呈现可能并不合适。

与静态渲染相反的是动态渲染。

什么是动态渲染?

通过动态呈现,服务器会在请求时(用户访问页面时)为每个用户呈现内容。动态呈现有几个好处:

  • 实时数据:动态渲染可让您的应用程序显示实时或经常更新的数据。这非常适合数据经常变化的应用。
  • 用户特定内容:提供仪表盘或用户配置文件等个性化内容,并根据用户互动更新数据,变得更加容易。
  • 请求时信息:动态呈现允许您访问只能在请求时才能知道的信息,如 cookie 或 URL 搜索参数。

让仪表盘充满活力

默认情况下, @vercel/postgres 不设置自己的缓存语义。这允许框架设置自己的静态和动态行为。

您可以在服务器组件或数据获取函数中使用名为 unstable_noStore 的 Next.js API,以选择退出静态模式。让我们添加以下内容。

在 data.ts 中,从 next/cache 导入 unstable_noStore ,并在数据获取函数的顶部调用它:

// /app/lib/data.ts
// ...
import { unstable_noStore as noStore } from 'next/cache';
 
export async function fetchRevenue() {
  // Add noStore() here to prevent the response from being cached.
  // This is equivalent to in fetch(..., {cache: 'no-store'}).
  noStore();
 
  // ...
}
 
export async function fetchLatestInvoices() {
  noStore();
  // ...
}
 
export async function fetchCardData() {
  noStore();
  // ...
}
 
export async function fetchFilteredInvoices(
  query: string,
  currentPage: number,
) {
  noStore();
  // ...
}
 
export async function fetchInvoicesPages(query: string) {
  noStore();
  // ...
}
 
export async function fetchFilteredCustomers(query: string) {
  noStore();
  // ...
}
 
export async function fetchInvoiceById(query: string) {
  noStore();
  // ...
}

模拟慢速数据读取

使仪表盘动态化是第一步。但是......我们在上一章中提到过一个问题。如果一个数据请求比其他所有请求都慢,会发生什么情况?

让我们来模拟一次缓慢的数据获取。在 data.ts 文件中,取消 console.log 和 setTimeout 中 fetchRevenue() 的注释:

// /app/lib/data.tx
export async function fetchRevenue() {
  try {
    // We artificially delay a response for demo purposes.
    // Don't do this in production :)
    console.log('Fetching revenue data...');
    await new Promise((resolve) => setTimeout(resolve, 3000));
 
    const data = await sql<Revenue>`SELECT * FROM revenue`;
 
    console.log('Data fetch completed after 3 seconds.');
 
    return data.rows;
  } catch (error) {
    console.error('Database Error:', error);
    throw new Error('Failed to fetch revenue data.');
  }
}

现在在新标签页中打开 http://localhost:3000/dashboard/,注意页面加载所需的时间。在终端中,你还应该看到以下信息:

Fetching revenue data...
Data fetch completed after 3 seconds.

在这里,你人为地添加了 3 秒钟的延迟来模拟缓慢的数据获取。这样做的结果是,在获取数据的过程中,整个页面都被阻塞了。

这就给我们带来了开发人员必须解决的一个共同难题:采用动态渲染后,应用程序的速度只能与最慢的数据获取速度相当。