一看就会的Next.js App Router版 -- Data Fetching(三)

简介: 一看就会的Next.js App Router版 -- Data Fetching

app/user/[id]/page.tsx


import { getUser } from '@utils/getUser';
export default async function Page({
  params: { id },
}: {
  params: { id: string };
}) {
  const user = await getUser(id);
  // ...
}

Although the getUser() function is called twice in the example above, only one query will be made to the database. This is because getUser() is wrapped in cache(), so the second request can reuse the result from the first request.

虽然在上面的示例中调用了两次 getUser() 函数,但只会对数据库进行一次查询。这是因为 getUser() 被包裹在 cache() 中,所以第二个请求可以重用第一个请求的结果。

Good to know:

  • fetch() caches requests automatically, so you don't need to wrap functions that use fetch() with cache(). See automatic request deduping for more information.
  • fetch() 自动缓存请求,所以你不需要用 cache() 包装使用 fetch() 的函数。有关详细信息,请参阅自动请求重复数据删除。
  • In this new model, we recommend fetching data directly in the component that needs it, even if you're requesting the same data in multiple components, rather than passing the data between components as props.
  • 在这个新模型中,我们建议直接在需要它的组件中获取数据,即使您在多个组件中请求相同的数据,而不是在组件之间将数据作为 props 传递。
  • We recommend using the server-only package to make sure server data fetching functions are never used on the client.
  • 我们建议使用 server-only 包来确保服务器数据获取功能永远不会在客户端上使用。

GraphQL and cache()

GraphQL 和缓存()

POST requests are automatically deduplicated when using fetch – unless they are inside of POST Route Handler or come after reading headers()/cookies(). If you are using GraphQL and POST requests in the above cases, you can use cache to deduplicate requests. The cache arguments must be flat and only include primitives. Deep objects won't match for deduplication.

使用 fetch 时,POST 请求会自动删除重复数据——除非它们在 POST 路由处理程序内部或在读取 headers()/cookies() 之后出现。如果您在上述情况下使用 GraphQL 和 POST 请求,则可以使用缓存对请求进行去重。缓存参数必须是平面的并且只包含基元。深层对象不适合重复数据删除。

utils/getUser.ts

import { cache } from 'react';
export const getUser = cache(async (id: string) => {
  const res = await fetch('/graphql', { method: 'POST', body: '...' });
  // ...
});

Preload pattern with cache()

使用 cache() 预加载模式

As a pattern, we suggest optionally exposing a preload() export in utilities or components that do data fetching.

作为一种模式,我们建议有选择地在执行数据获取的实用程序或组件中公开 preload() 导出。

components/User.tsx

import { getUser } from '@utils/getUser';
export const preload = (id: string) => {
  // void evaluates the given expression and returns undefined
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void
  void getUser(id);
};
export default async function User({ id }: { id: string }) {
  const result = await getUser(id);
  // ...
}

By calling preload, you can eagerly start fetching data you're likely going to need.

通过调用预加载,您可以急切地开始获取您可能需要的数据。

app/user/[id]/page.tsx

import User, { preload } from '@components/User';
export default async function Page({
  params: { id },
}: {
  params: { id: string };
}) {
  preload(id); // starting loading the user data now
  const condition = await fetchCondition();
  return condition ? <User id={id} /> : null;
}

Good to know:

很高兴知道:

  • The preload() function can have any name. It's a pattern, not an API.
  • preload() 函数可以有任何名称。它是一种模式,而不是 API。
  • This pattern is completely optional and something you can use to optimize on a case-by-case basis. This pattern is a further optimization on top of parallel data fetching. Now you don't have to pass promises down as props and can instead rely on the preload pattern.
  • 这种模式是完全可选的,您可以根据具体情况使用它来优化。这种模式是在并行数据获取之上的进一步优化。现在您不必将 promise 作为 props 传递下去,而是可以依赖预加载模式。

Combining cache, preload, and server-only

结合缓存、预加载和仅服务器

You can combine the cache function, the preload pattern, and the server-only package to create a data fetching utility that can be used throughout your app.

您可以结合缓存功能、预加载模式和仅限服务器的包来创建可在整个应用程序中使用的数据获取实用程序。

utils/getUser.ts

import { cache } from 'react';
import 'server-only';
export const preload = (id: string) => {
  void getUser(id);
};
export const getUser = cache(async (id: string) => {
  // ...
});

With this approach, you can eagerly fetch data, cache responses, and guarantee that this data fetching only happens on the server.

使用这种方法,您可以急切地获取数据、缓存响应,并保证此数据获取仅发生在服务器上。

The getUser.ts exports can be used by layouts, pages, or components to give them control over when a user's data is fetched.

布局、页面或组件可以使用 getUser.ts 导出来控制何时获取用户数据。

Segment-level Caching

段级缓存

Note: We recommend using per-request caching for improved granularity and control over caching.

注意:我们建议使用按请求缓存来提高粒度和对缓存的控制。

Segment-level caching allows you to cache and revalidate data used in route segments.

段级缓存允许您缓存和重新验证路由段中使用的数据。

This mechanism allows different segments of a path to control the cache lifetime of the entire route. Each page.tsx and layout.tsx in the route hierarchy can export a revalidate value that sets the revalidation time for the route.

这种机制允许路径的不同段来控制整个路由的缓存生命周期。路由层次结构中的每个 page.tsx 和 layout.tsx 都可以导出一个 revalidate 值,该值设置路由的重新生效时间。

app/page.tsx

export const revalidate = 60; // revalidate this segment every 60 seconds

Good to know:

很高兴知道:

  • If a page, layout, and fetch request all specify a revalidate frequency, the lowest value of the three will be used.
  • 如果页面、布局和获取请求都指定了重新验证频率,则将使用三者中的最低值。
  • Advanced: You can set fetchCache to 'only-cache' or 'force-cache' to ensure that all fetch requests opt into caching but the revalidation frequency might still be lowered by individual fetch requests. See fetchCache for more information.
  • 高级:您可以将 fetchCache 设置为 'only-cache' 或 'force-cache' 以确保所有提取请求都选择缓存,但重新验证频率可能仍会因单个提取请求而降低。有关详细信息,请参阅获取缓存。

Revalidating Data

重新验证数据

Next.js allows you to update specific static routes without needing to rebuild your entire site. Revalidation (also known as Incremental Static Regeneration) allows you to retain the benefits of static while scaling to millions of pages.

Next.js 允许您更新特定的静态路由,而无需重建整个站点。重新验证(也称为增量静态重新生成)允许您在扩展到数百万页的同时保留静态的好处。

There are two types of revalidation in Next.js:

Next.js 中有两种类型的重新验证:

  • Background: Revalidates the data at a specific time interval.
  • 背景:以特定时间间隔重新验证数据。
  • On-demand: Revalidates the data based on an event such as an update.
  • 按需:根据更新等事件重新验证数据。

Background Revalidation

背景重新验证

To revalidate cached data at a specific interval, you can use the next.revalidate option in fetch() to set the cache lifetime of a resource (in seconds).

要以特定时间间隔重新验证缓存数据,您可以使用 fetch() 中的 next.revalidate 选项来设置资源的缓存生命周期(以秒为单位)。

fetch('https://...', { next: { revalidate: 60 } });

If you want to revalidate data that does not use fetch (i.e. using an external package or query builder), you can use the route segment config.

如果你想重新验证不使用获取的数据(即使用外部包或查询构建器),你可以使用路由段配置。

app/page.tsx

export const revalidate = 60; // revalidate this page every 60 seconds
In addition to fetch, you can also revalidate data using cache.

除了获取之外,您还可以使用缓存重新验证数据。

How it works

怎么运行的

  1. When a request is made to the route that was statically rendered at build time, it will initially show the cached data.
    当对在构建时静态呈现的路由发出请求时,它最初将显示缓存的数据。
  2. Any requests to the route after the initial request and before 60 seconds are also cached and instantaneous.
    在初始请求之后和 60 秒之前对路由的任何请求也被缓存和即时。
  3. After the 60-second window, the next request will still show the cached (stale) data.
    在 60 秒窗口之后,下一个请求仍将显示缓存的(陈旧的)数据。
  4. Next.js will trigger a regeneration of the data in the background.
    Next.js 将在后台触发数据的重新生成。
  5. Once the route generates successfully, Next.js will invalidate the cache and show the updated route. If the background regeneration fails, the old data would still be unaltered.
    路由生成成功后,Next.js 将使缓存失效并显示更新后的路由。如果后台重新生成失败,旧数据仍将保持不变。

When a request is made to a route segment that hasn’t been generated, Next.js will dynamically render the route on the first request. Future requests will serve the static route segments from the cache.

当向尚未生成的路由段发出请求时,Next.js 将在第一个请求时动态呈现路由。未来的请求将服务于缓存中的静态路由段。

Note: Check if your upstream data provider has caching enabled by default. You might need to disable (e.g. useCdn: false), otherwise a revalidation won't be able to pull fresh data to update the ISR cache. Caching can occur at a CDN (for an endpoint being requested) when it returns the Cache-Control header. ISR on Vercel persists the cache globally and handles rollbacks.

注意:检查您的上游数据提供者是否默认启用了缓存。您可能需要禁用(例如 useCdn: false),否则重新验证将无法提取新数据来更新 ISR 缓存。当 CDN 返回 Cache-Control 标头时,缓存可以发生在 CDN(对于被请求的端点)。 Vercel 上的 ISR 在全局范围内保留缓存并处理回滚 .

On-demand Revalidation

按需重新验证

If you set a revalidate time of 60, all visitors will see the same generated version of your site for one minute. The only way to invalidate the cache is if someone visits the page after the minute has passed.

如果您将重新验证时间设置为 60,则所有访问者将在一分钟内看到您网站的相同生成版本。使缓存无效的唯一方法是在一分钟后有人访问该页面。

The Next.js App Router supports revalidating content on-demand based on a route or cache tag. This allows you to manually purge the Next.js cache for specific fetches, making it easier to update your site when:

Next.js App Router 支持基于路由或缓存标签按需重新验证内容。这使您可以手动清除特定提取的 Next.js 缓存,从而在以下情况下更轻松地更新您的站点:

  • Content from your headless CMS is created or updated.
  • 创建或更新来自无外设 CMS 的内容。
  • Ecommerce metadata changes (price, description, category, reviews, etc).
  • 电子商务元数据更改(价格、描述、类别、评论等)。

Using On-Demand Revalidation

使用按需重新验证

Data can be revalidated on-demand by path (revalidatePath) or by cache tag (revalidateTag).

可以通过路径 (revalidatePath) 或缓存标记 (revalidateTag) 按需重新验证数据。

For example, the following fetch adds the cache tag collection:

例如,下面的 fetch 添加了缓存标签集合:

app/page.tsx

export const revalidate = 60; // revalidate this page every 60 seconds
In addition to fetch, you can also revalidate data using cache.

This cached data can then be revalidated on-demand by calling revalidateTag in a Route Handler.

然后可以通过在路由处理程序中调用 revalidateTag 按需重新验证此缓存数据。

app/api/revalidate/route.ts

import { NextRequest, NextResponse } from 'next/server';
import { revalidateTag } from 'next/cache';
export async function GET(request: NextRequest) {
  const tag = request.nextUrl.searchParams.get('tag');
  revalidateTag(tag);
  return NextResponse.json({ revalidated: true, now: Date.now() });
}

Error Handling and Revalidation

错误处理和重新验证

If an error is thrown while attempting to revalidate data, the last successfully generated data will continue to be served from the cache. On the next subsequent request, Next.js will retry revalidating the data.

如果在尝试重新验证数据时抛出错误,则将继续从缓存中提供最后成功生成的数据。在下一个后续请求中,Next.js 将重新尝试重新验证数据。

Server Actions

服务器操作

Server Actions are an alpha feature in Next.js, built on top of React Actions. They enable server-side data mutations, reduced client-side JavaScript, and progressively enhanced forms.

Server Actions 是 Next.js 中的一个 alpha 特性,它建立在 React Actions 之上。它们支持服务器端数据突变、减少客户端 JavaScript 和逐步增强的表单。

app/add-to-cart.js

import { cookies } from 'next/headers';
export default function AddToCart({ productId }) {
  async function addItem(data) {
    'use server';
    const cartId = cookies().get('cartId')?.value;
    await saveToDb({ cartId, data });
  }
  return (
    <form action={addItem}>
      <button type="submit">Add to Cart</button>
    </form>
  );
}

Convention

You can enable Server Actions in your Next.js project by enabling the experimentalserverActions flag.

您可以通过启用实验性 serverActions 标志在 Next.js 项目中启用服务器操作。

next.config.js

module.exports = {  experimental: {    serverActions: true,  },};

Creation

目录
相关文章
|
30天前
|
小程序 JavaScript 前端开发
uni-app开发微信小程序:四大解决方案,轻松应对主包与vendor.js过大打包难题
uni-app开发微信小程序:四大解决方案,轻松应对主包与vendor.js过大打包难题
504 1
|
2月前
|
监控 JavaScript 前端开发
深入理解 Nuxt.js 中的 app:error 钩子
【9月更文挑战第25天】在 Nuxt.js 中,`app:error` 钩子是一个强大的工具,用于处理应用程序中的各种错误。它可以在服务器端渲染或客户端运行时触发,帮助提升应用稳定性和用户体验。通过在 `nuxt.config.js` 中定义该钩子,开发者可以实现错误页面显示、错误日志记录及错误恢复等功能,确保应用在遇到问题时能妥善处理并恢复正常运行。
48 10
|
3月前
|
资源调度 JavaScript Linux
【Azure 应用服务】本地Node.js部署上云(Azure App Service for Linux)遇到的三个问题解决之道
【Azure 应用服务】本地Node.js部署上云(Azure App Service for Linux)遇到的三个问题解决之道
|
2月前
|
开发者 UED
深入理解 Nuxt.js 中的 app:error 钩子
【9月更文挑战第26天】在 Nuxt.js 中,钩子函数是在特定生命周期阶段执行代码的机制,`app:error` 钩子用于处理应用中的错误,包括服务器端和客户端渲染时出现的问题。它提供了一个集中处理错误的机制,提升了用户体验。当组件渲染过程中出现错误时,`app:error` 钩子会被触发,可以在 `nuxt.config.js` 文件中定义该钩子。通过分析错误对象 `err` 和上下文信息 `context`,开发者可以更好地处理各种错误情况。相比组件内的 `try/catch` 或浏览器原生错误处理,`app:error` 提供了更全局和有针对性的错误处理方式。
|
3月前
【Azure Function App】在ADF(Azure Data Factory)中调用 Azure Function 时候遇见 Failed to get MI access token
【Azure Function App】在ADF(Azure Data Factory)中调用 Azure Function 时候遇见 Failed to get MI access token
|
3月前
|
JavaScript 前端开发
【Azure Developer】在App Service上放置一个JS页面并引用msal.min.js成功获取AAD用户名示例
【Azure Developer】在App Service上放置一个JS页面并引用msal.min.js成功获取AAD用户名示例
|
3月前
|
JavaScript 前端开发 UED
揭秘Vue.js高效开发:Vue Router如何让单页面应用路由管理变得如此简单?
【8月更文挑战第30天】随着Web应用复杂性的增加,单页面应用(SPA)因出色的用户体验和高效的页面加载性能而备受青睐。Vue.js凭借简洁的语法和灵活的组件系统成为构建SPA的热门选择,其官方路由管理器Vue Router则简化了路由管理。本文通过实战示例介绍如何利用Vue Router实现高效的SPA路由管理,包括命名路由、动态路由及其核心优势。
35 0
|
3月前
|
网络协议
【Azure 应用服务】Azure Data Factory中调用Function App遇见403 - Forbidden
【Azure 应用服务】Azure Data Factory中调用Function App遇见403 - Forbidden
|
3月前
|
JavaScript Windows
【Azure 应用服务】用App Service部署运行 Vue.js 编写的项目,应该怎么部署运行呢?
【Azure 应用服务】用App Service部署运行 Vue.js 编写的项目,应该怎么部署运行呢?
|
3月前
|
开发框架 JavaScript 前端开发
【Azure Developer】App Service + PubSub +JS 实现多人版黑客帝国文字流效果图
【Azure Developer】App Service + PubSub +JS 实现多人版黑客帝国文字流效果图

热门文章

最新文章