一看就会的Next.js App Router版 -- Routing(上)(二)

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

Prefetching

预取

Prefetching is a way to preload a route in the background before it's visited. The rendered result of prefetched routes is added to the router's client-side cache. This makes navigating to a prefetched route near-instant.

预取是一种在访问路由之前在后台预加载路由的方法。预取路由的渲染结果被添加到路由器的客户端缓存中。这使得导航到预取路线近乎即时。

By default, routes are prefetched as they become visible in the viewport when using the <Link> component. This can happen when the page first loads or through scrolling. Routes can also be programmatically prefetched using the prefetch method of the useRouter() hook.

默认情况下,当使用  组件时,路由在视口中可见时会被预取。这可能会在页面首次加载或滚动时发生。也可以使用 useRouter() 挂钩的预取方法以编程方式预取路由。

Static and Dynamic Routes:

静态和动态路由:

  • If the route is static, all the Server Component payloads for the route segments will be prefetched.
  • 如果路由是静态的,路由段的所有服务器组件负载都将被预取。
  • If the route is dynamic, the payload from the first shared layout down until the first loading.js file is prefetched. This reduces the cost of prefetching the whole route dynamically and allows instant loading states for dynamic routes.
  • 如果路由是动态的,则预取从第一个共享布局到第一个 loading.js 文件的有效负载。这降低了动态预取整个路由的成本,并允许动态路由的即时加载状态。

Good to know:

很高兴知道:

  • Prefetching is only enabled in production.
  • 预取仅在生产中启用。
  • Prefetching can be disabled by passing prefetch={false} to <Link>.
  • 可以通过将 prefetch={false} 传递给  来禁用预取。

Hard Navigation

硬导航

On navigation, the cache is invalidated and the server refetches data and re-renders the changed segments.

在导航时,缓存失效,服务器重新获取数据并重新呈现更改的段。

Soft Navigation

软导航

On navigation, the cache for changed segments is reused (if it exists), and no new requests are made to the server for data.

在导航时,更改段的缓存将被重用(如果存在),并且不会向服务器发出新的数据请求。

Conditions for Soft Navigation

软导航的条件

On navigation, Next.js will use soft navigation if the route you are navigating to has been prefetched, and either doesn't include dynamic segmentsor has the same dynamic parameters as the current route.

在导航方面,如果您导航到的路线已被预取,并且不包含动态段或具有与当前路线相同的动态参数,则 Next.js 将使用软导航。

For example, consider the following route that includes a dynamic [team] segment: /dashboard/[team]/*. The cached segments below /dashboard/[team]/* will only be invalidated when the [team] parameter changes.

例如,考虑以下包含动态 [team] 段的路由:/dashboard/[team]/。 /dashboard/[team]/ 下面的缓存段只会在 [team] 参数发生变化时失效。

  • Navigating from /dashboard/team-red/* to /dashboard/team-red/* will be a soft navigation.
  • 从 /dashboard/team-red/* 导航到 /dashboard/team-red/* 将是一个软导航。
  • Navigating from /dashboard/team-red/* to /dashboard/team-blue/* will be a hard navigation.
  • 从 /dashboard/team-red/* 导航到 /dashboard/team-blue/* 将是一个艰难的导航。

Back/Forward Navigation

后退/前进导航

Back and forward navigation (popstate event) has a soft navigation behavior. This means, the client-side cache is re-used and navigation is near-instant.

前后导航(popstate 事件 ) 具有软导航行为。这意味着,客户端缓存被重新使用,导航几乎是即时的。

Focus and Scroll Management

焦点和滚动管理

By default, Next.js will set focus and scroll into view the segment that's changed on navigation.

默认情况下,Next.js 将设置焦点并滚动到查看导航更改的部分。

Routes Groups

路线组

The hierarchy of the app folder maps directly to URL paths. However, it’s possible to break out of this pattern by creating a route group. Route groups can be used to:

应用程序文件夹的层次结构直接映射到 URL 路径。但是,可以通过创建路由组来打破这种模式。路由组可用于:

  • Organize routes without affecting the URL structure.
  • 在不影响 URL 结构的情况下组织路由。
  • Opting-in specific route segments into a layout.
  • 选择将特定路线段加入布局。
  • Create multiple root layouts by splitting your application.
  • 通过拆分您的应用程序来创建多个根布局。

Convention

A route group can be created by wrapping a folder’s name in parenthesis: (folderName)

可以通过将文件夹名称括在括号中来创建路由组:(folderName)

Examples

例子

Organize routes without affecting the URL path

在不影响 URL 路径的情况下组织路由

To organize routes without affecting the URL, create a group to keep related routes together. The folders in parenthesis will be omitted from the URL (e.g. (marketing) or (shop)).

要在不影响 URL 的情况下组织路由,请创建一个组以将相关路由放在一起。括号中的文件夹将从 URL 中省略(例如 (marketing) 或 (shop))。

image.png

Even though routes inside (marketing) and (shop) share the same URL hierarchy, you can create a different layout for each group by adding a layout.js file inside their folders.

即使 (marketing) 和 (shop) 中的路由共享相同的 URL 层次结构,您也可以通过在其文件夹中添加 layout.js 文件来为每个组创建不同的布局。

image.png

Opting specific segments into a layout

将特定段选择到布局中

To opt specific routes into a layout, create a new route group (e.g. (shop)) and move the routes that share the same layout into the group (e.g. account and cart). The routes outside of the group will not share the layout (e.g. checkout).

要将特定路线选择到布局中,请创建一个新路线组(例如(商店))并将共享相同布局的路线移动到该组中(例如帐户和购物车)。组外的路线不会共享布局(例如结帐)。

image.png

Creating multiple root layouts

创建多个根布局

To create multiple root layouts, remove the top-level layout.js file, and add a layout.js file inside each route groups. This is useful for partitioning an application into sections that have a completely different UI or experience. The <html> and <body> tags need to be added to each root layout.

要创建多个根布局,请删除顶级 layout.js 文件,并在每个路由组中添加一个 layout.js 文件。这对于将应用程序划分为具有完全不同的 UI 或体验的部分非常有用。  和  标签需要添加到每个根布局。

image.png

In the example above, both (marketing) and (shop) have their own root layout.

在上面的示例中,(marketing) 和 (shop) 都有自己的根布局。

Good to know

很高兴知道

  • The naming of route groups has no special significance other than for organization. They do not affect the URL path.
  • 路由组的命名除了组织之外没有特殊意义。它们不影响 URL 路径。
  • Routes inside route groups should not resolve to the same URL path. For example, since route groups don't affect URL structure, (marketing)/about/page.js and (shop)/about/page.js would both resolve to /about and cause an error.
  • 路由组内的路由不应解析为相同的 URL 路径。例如,由于路由组不影响 URL 结构,(marketing)/about/page.js 和 (shop)/about/page.js 都会解析为 /about 并导致错误。
  • Navigating across multiple root layouts will cause a full page load (as opposed to a client-side navigation). For example, navigating from /cart that uses app/(shop)/layout.js to /blog that uses app/(marketing)/layout.js will cause a full page load. This only applies to multiple root layouts.
  • 跨多个根布局导航将导致整个页面加载(与客户端导航相反)。例如,从使用 app/(shop)/layout.js 的 /cart 导航到使用 app/(marketing)/layout.js 的 /blog 将导致整个页面加载。这仅适用于多根布局。

Dynamic Routes

动态路线

When you don't know the exact segment names ahead of time and want to create routes from dynamic data, you can use Dynamic Segments that are filled in at request time or prerendered at build time.

当您事先不知道确切的路段名称并希望从动态数据创建路线时,您可以使用在请求时填写或在构建时预呈现的动态路段。

Convention

习俗

A Dynamic Segment can be created by wrapping a folder's name in square brackets: [folderName]. For example, [id] or [slug].

可以通过将文件夹名称括在方括号中来创建动态细分:[folderName]。例如,[id] 或 [slug]。

Dynamic Segments are passed as the params prop to layout, page, route, and generateMetadata functions.

动态细分作为 params 属性传递给布局、页面、路由和生成元数据函数。

Example

例子

For example, a blog could include the following route app/blog/[slug]/page.js where [slug] is the Dynamic Segment for blog posts.

例如,博客可以包含以下路由 app/blog/[slug]/page.js,其中 [slug] 是博客文章的动态部分。

app/blog/[slug]/page.js

export async function generateStaticParams() {
  const posts = await fetch('https://.../posts').then((res) => res.json());
  return posts.map((post) => ({
    slug: post.slug,
  }));
}
Route Example URL params
app/blog/[slug]/page.js /blog/a { slug: 'a' }
app/blog/[slug]/page.js /blog/b { slug: 'b' }
app/blog/[slug]/page.js /blog/c { slug: 'c' }

See the generateStaticParams() page to learn how to generate the params for the segment.

请参阅 generateStaticParams() 页面以了解如何为段生成参数。

Note: Dynamic Segments are equivalent to Dynamic Routes in the pages directory.

注意:Dynamic Segments 相当于 pages 目录下的 Dynamic Routes。

Generating Static Params

生成静态参数

The generateStaticParams function can be used in combination with dynamic route segments to statically generate routes at build time instead of on-demand at request time.

generateStaticParams 函数可以与动态路由段结合使用,以在构建时静态生成路由,而不是在请求时按需生成路由。

app/blog/[slug]/page.tsx

export async function generateStaticParams() {
  const posts = await fetch('https://.../posts').then((res) => res.json());
  return posts.map((post) => ({
    slug: post.slug,
  }));
}

The primary benefit of the generateStaticParams function is its smart retrieval of data. If content is fetched within the generateStaticParams function using a fetch request, the requests are automatically deduplicated. This means a fetch request with the same arguments across multiple generateStaticParams, Layouts, and Pages will only be made once, which decreases build times.

generateStaticParams 函数的主要好处是它可以智能检索数据。如果使用提取请求在 generateStaticParams 函数中提取内容,则会自动对请求进行重复数据删除。这意味着跨多个 generateStaticParams、Layouts 和 Pages 的具有相同参数的获取请求将只会发出一次,从而减少了构建时间。

Use the migration guide if you are migrating from the pages directory.

如果您要从页面目录迁移,请使用迁移指南。

See generateStaticParams server function documentation for more information and advanced use cases.

有关更多信息和高级用例,请参阅 generateStaticParams 服务器函数文档。

Catch-all Segments

包罗万象的细分市场

Dynamic Segments can be extended to catch-all subsequent segments by adding an ellipsis inside the brackets [...folderName].

通过在方括号 [...folderName] 内添加省略号,可以将动态段扩展为包含所有后续段。

For example, app/shop/[...slug]/page.js will match /shop/clothes, but also /shop/clothes/tops, /shop/clothes/tops/t-shirts, and so on.

例如,app/shop/[...slug]/page.js 将匹配 /shop/clothes,但也匹配 /shop/clothes/tops、/shop/clothes/tops/t-shirts 等。

Route Example URL params
app/shop/[...slug]/page.js /shop/a { slug: ['a'] }
app/shop/[...slug]/page.js /shop/a/b { slug: ['a', 'b'] }
app/shop/[...slug]/page.js /shop/a/b/c { slug: ['a', 'b', 'c'] }

Optional Catch-all Segments

可选的全包段

Catch-all Segments can be made optional by including the parameter in double square brackets: [[...folderName]].

通过在双方括号中包含参数,可以使 Catch-all Segments 成为可选的:[[...folderName]]。

For example, app/shop/[[...slug]]/page.js will also match /shop, in addition to /shop/clothes, /shop/clothes/tops, /shop/clothes/tops/t-shirts.

比如app/shop/[[...slug]]/page.js也会匹配/shop,除了/shop/clothes, /shop/clothes/tops, /shop/clothes/tops/t-shirts .

The difference between catch-all and optional catch-all segments is that with optional, the route without the parameter is also matched (/shop in the example above).

catch-all 和 optional catch-all segments 的区别在于,使用 optional 时,不带参数的路由也会被匹配(上例中的 /shop)。

Route Example URL params
app/shop/[[...slug]]/page.js /shop {}
app/shop/[[...slug]]/page.js /shop/a { slug: ['a'] }
app/shop/[[...slug]]/page.js /shop/a/b { slug: ['a', 'b'] }
app/shop/[[...slug]]/page.js /shop/a/b/c { slug: ['a', 'b', 'c'] }

TypeScript

When using TypeScript, you can add types for params depending on your configured route segment.

使用 TypeScript 时,您可以根据配置的路由段为参数添加类型。

app/blog/[slug]/page.tsx

js

复制代码

exportdefaultfunctionPage({ params }: { params: { slug: string } }) {

 return<h1>My Page</h1>;

}

Route params Type Definition
app/blog/[slug]/page.js { slug: string }
app/shop/[...slug]/page.js { slug: string[] }
app/[categoryId]/[itemId]/page.js { categoryId: string, itemId: string }

Note: This may be done automatically by the TypeScript plugin in the future.

注意:这可能会在未来由 TypeScript 插件自动完成。

Loading UI and Streaming

加载 UI 和流式传输

The special file loading.js helps you create meaningful Loading UI with React Suspense. With this convention, you can show an instant loading state from the server while the content of a route segment loads, the new content is automatically swapped in once rendering is complete.

特殊文件 loading.js 可帮助您使用 React Suspense 创建有意义的加载 UI

.使用此约定,您可以在加载路由段的内容时显示来自服务器的即时加载状态,一旦渲染完成,新内容将自动交换。

Instant Loading States

即时加载状态

An instant loading state is fallback UI that is shown immediately upon navigation. You can pre-render loading indicators such as skeletons and spinners, or a small but meaningful part of future screens such as a cover photo, title, etc. This helps users understand the app is responding and provides a better user experience.

即时加载状态是在导航时立即显示的回退 UI。您可以预渲染加载指示器,如骨架和微调器,或未来屏幕的一小部分但有意义的部分,如封面照片、标题等。这有助于用户了解应用程序正在响应并提供更好的用户体验。

Create a loading state by adding a loading.js file inside a folder.

通过在文件夹中添加 loading.js 文件来创建加载状态。

image.png

app/dashboard/loading.tsx

export default function Loading() {
  // You can add any UI inside Loading, including a Skeleton.
  return <LoadingSkeleton />;
}

In the same folder, loading.js will be nested inside layout.js. It will automatically wrap the page.js file and any children below in a <Suspense> boundary.

在同一文件夹中,loading.js 将嵌套在 layout.js 中。它会自动将 page.js 文件和下面的任何子文件包装在  边界中。

image.png

Good to know:

很高兴知道:

  • Navigation is immediate, even with server-centric routing.
  • 导航是即时的,即使使用以服务器为中心的路由也是如此。
  • Navigation is interruptible, meaning changing routes does not need to wait for the content of the route to fully load before navigating to another route.
  • 导航是可中断的,这意味着更改路线不需要等待路线内容完全加载后再导航到另一条路线。
  • Shared layouts remain interactive while new route segments load.
  • 共享布局在加载新路线段时保持交互。

Recommendation: Use the loading.js convention for route segments (layouts and pages) as Next.js optimizes this functionality.

建议:对路由段(布局和页面)使用 loading.js 约定,因为 Next.js 优化了此功能。

Streaming with Suspense

In addition to loading.js, you can also manually create Suspense Boundaries for your own UI components. The App Router supports streaming with Suspense for both Node.js and Edge runtimes.

除了 loading.js 之外,您还可以为自己的 UI 组件手动创建 Suspense Boundaries。 App Router 支持使用 Suspense 进行流式传输 适用于 Node.js 和 Edge 运行时。

What is Streaming?

什么是流媒体?

To learn how Streaming works in React and Next.js, it's helpful to understand Server-Side Rendering (SSR) and its limitations.

要了解 Streaming 在 React 和 Next.js 中的工作原理,了解服务器端渲染 (SSR) 及其局限性很有帮助。

With SSR, there's a series of steps that need to be completed before a user can see and interact with a page:

使用 SSR,在用户可以查看页面并与之交互之前需要完成一系列步骤:

  1. First, all data for a given page is fetched on the server.
    首先,在服务器上获取给定页面的所有数据。
  2. The server then renders the HTML for the page.
    然后服务器呈现页面的 HTML。
  3. The HTML, CSS, and JavaScript for the page are sent to the client.
    页面的 HTML、CSS 和 JavaScript 被发送到客户端。
  4. A non-interactive user interface is shown using the generated HTML, and CSS.
    使用生成的 HTML 和 CSS 显示非交互式用户界面。
  5. Finally, React hydrates the user interface to make it interactive.
    最后,React 水合物 用户界面,使其具有交互性。

image.png

These steps are sequential and blocking, meaning the server can only render the HTML for a page once all the data has been fetched. And, on the client, React can only hydrate the UI once the code for all components in the page has been downloaded.

这些步骤是顺序的和阻塞的,这意味着服务器只能在获取所有数据后才能呈现页面的 HTML。而且,在客户端,React 只能在页面中所有组件的代码都已下载后才能对 UI 进行水合。

SSR with React and Next.js helps improve the perceived loading performance by showing a non-interactive page to the user as soon as possible.

使用 React 和 Next.js 的 SSR 通过尽快向用户显示非交互式页面来帮助提高感知加载性能。

image.png

However, it can still be slow as all data fetching on server needs to be completed before the page can be shown to the user.

但是,它仍然可能很慢,因为需要在页面显示给用户之前完成服务器上的所有数据获取。

Streaming allows you to break down the page's HTML into smaller chunks and progressively send those chunks from the server to the client.

Streaming 允许您将页面的 HTML 分解为更小的块,并逐步将这些块从服务器发送到客户端。

image.png

This enables parts of the page to be displayed sooner, without waiting for all the data to load before any UI can be rendered.

这使得部分页面能够更快地显示,而无需等待所有数据加载完毕才能呈现任何 UI。

Streaming works well with React's component model because each component can be considered a chunk. Components that have higher priority (e.g. product information) or that don't rely on data can be sent first (e.g. layout), and React can start hydration earlier. Components that have lower priority (e.g. reviews, related products) can be sent in the same server request after their data has been fetched.

Streaming 与 React 的组件模型配合得很好,因为每个组件都可以被视为一个块。优先级较高的组件(例如产品信息)或不依赖数据的组件可以先发送(例如布局),React 可以更早地开始水合。具有较低优先级的组件(例如评论、相关产品)可以在获取数据后在同一服务器请求中发送。

image.png

Streaming is particularly beneficial when you want to prevent long data requests from blocking the page from rendering as it can reduce the Time To First Byte (TTFB) and First Contentful Paint (FCP). It also helps improve Time to Interactive (TTI), especially on slower devices.

当您想要防止长数据请求阻止页面呈现时,流式处理特别有用,因为它可以减少首字节时间 (TTFB)  和第一内容绘画(FCP)  它还有助于改善交互时间 (TTI)  ,尤其是在速度较慢的设备上。

Example

<Suspense> works by wrapping a component that performs an asynchronous action (e.g. fetch data), showing fallback UI (e.g. skeleton, spinner) while it's happening, and then swapping in your component once the action completes.

<Suspense> 的工作原理是包装一个执行异步操作(例如获取数据)的组件,在它发生时显示回退 UI(例如骨架、微调器),然后在操作完成后交换您的组件。

app/dashboard/page.tsx

import { Suspense } from 'react';
import { PostFeed, Weather } from './Components';
export default function Posts() {
  return (
    <section>
      <Suspense fallback={<p>Loading feed...</p>}>
        <PostFeed />
      </Suspense>
      <Suspense fallback={<p>Loading weather...</p>}>
        <Weather />
      </Suspense>
    </section>
  );
}

By using Suspense, you get the benefits of:

通过使用 Suspense,您可以获得以下好处:

  1. Streaming Server Rendering - Progressively rendering HTML from the server to the client. Streaming Server Rendering - 从服务器到客户端逐步渲染 HTML。
  2. Selective Hydration - React prioritizes what components to make interactive first based on user interaction. Selective Hydration - React 根据用户交互优先考虑哪些组件首先进行交互。

For more Suspense examples and use cases, please see the React Documentation.

有关更多 Suspense 示例和用例,请参阅 React 文档

SEO

  • Next.js will wait for data fetching inside generateMetadata to complete before streaming UI to the client. This guarantees the first part of a streamed response includes <head> tags.
  • Next.js 将等待 generateMetadata 中的数据获取完成,然后再将 UI 流式传输到客户端。这保证了流式响应的第一部分包含  标签。
  • Since streaming is server-rendered, it does not impact SEO. You can use the Mobile Friendly Test tool from Google to see how your page appears to Google's web crawlers and view the serialized HTML (source).
  • 由于流式传输是服务器呈现的,因此不会影响 SEO。您可以使用移动友好测试
    来自 Google 的工具,用于查看您的页面如何出现在 Google 的网络爬虫中并查看序列化的 HTML(来源 ).

Error Handling

错误处理

The error.js file convention allows you to gracefully handle runtime errors in nested routes.

error.js 文件约定允许您优雅地处理嵌套路由中的运行时错误。

  • Automatically wrap a route segment and its nested children in a React Error Boundary.
  • 自动将路由段及其嵌套子项包装在 React 错误边界中
  • Create error UI tailored to specific segments using the file-system hierarchy to adjust granularity.
  • 使用文件系统层次结构来创建针对特定细分量身定制的错误 UI 以调整粒度。
  • Isolate errors to affected segments while keeping the rest of the app functional.
  • 将错误隔离到受影响的部分,同时保持应用程序的其余部分正常运行。
  • Add functionality to attempt to recover from an error without a full page reload.
  • 添加功能以尝试在不重新加载整页的情况下从错误中恢复。

Create error UI by adding an error.js file inside a route segment and exporting a React component:

通过在路由段内添加 error.js 文件并导出 React 组件来创建错误 UI:

image.png

app/dashboard/error.tsx

'use client'; // Error components must be Client components
import { useEffect } from 'react';
export default function Error({
  error,
  reset,
}: {
  error: Error;
  reset: () => void;
}) {
  useEffect(() => {
    // Log the error to an error reporting service
    console.error(error);
  }, [error]);
  return (
    <div>
      <h2>Something went wrong!</h2>
      <button
        onClick={
          // Attempt to recover by trying to re-render the segment
          () => reset()
        }
      >
        Try again
      </button>
    </div>
  );
}

How error.js Works

error.js 是如何工作的

image.png

  • error.js automatically creates an React Error Boundary that wraps a nested child segment or page.js component.
  • error.js 自动创建一个 React 错误边界包装嵌套的子段或 page.js 组件。
  • The React component exported from the error.js file is used as the fallback component.
  • 从 error.js 文件导出的 React 组件用作回退组件。
  • If an error is thrown within the error boundary, the error is contained, and the fallback component is rendered.
  • 如果在错误边界内抛出错误,则包含错误,并呈现回退组件。
  • When the fallback error component is active, layouts above the error boundary maintain their state and remain interactive, and the error component can display functionality to recover from the error.
  • 当回退错误组件处于活动状态时,错误边界上方的布局会保持其状态并保持交互,并且错误组件可以显示从错误中恢复的功能。

Recovering From Errors

从错误中恢复

The cause of an error can sometimes be temporary. In these cases, simply trying again might resolve the issue.

错误的原因有时可能是暂时的。在这些情况下,只需重试即可解决问题。

An error component can use the reset() function to prompt the user to attempt to recover from the error. When executed, the function will try to re-render the Error boundary's contents. If successful, the fallback error component is replaced with the result of the re-render.

错误组件可以使用 reset() 函数来提示用户尝试从错误中恢复。执行时,该函数将尝试重新呈现错误边界的内容。如果成功,回退错误组件将替换为重新渲染的结果。

app/dashboard/error.ts

'use client';
export default function Error({
  error,
  reset,
}: {
  error: Error;
  reset: () => void;
}) {
  return (
    <div>
      <h2>Something went wrong!</h2>
      <button onClick={() => reset()}>Try again</button>
    </div>
  );
}

Nested Routes

嵌套路由

React components created through special files are rendered in a specific nested hierarchy.

通过特殊文件创建的 React 组件在特定的嵌套层次结构中呈现。

For example, a nested route with two segments that both include layout.js and error.js files are rendered in the following simplified component hierarchy:

例如,包含两个段的嵌套路由都包含 layout.js 和 error.js 文件,在以下简化的组件层次结构中呈现:

image.png

The nested component hierarchy has implications for the behavior of error.js files across a nested route:

嵌套组件层次结构对跨嵌套路由的 error.js 文件的行为有影响:

  • Errors bubble up to the nearest parent error boundary. This means an error.js file will handle errors for all its nested child segments. More or less granular error UI can be achieved by placing error.js files at different levels in the nested folders of a route.
  • 错误冒泡到最近的父错误边界。这意味着 error.js 文件将处理其所有嵌套子段的错误。通过将 error.js 文件放置在路由的嵌套文件夹中的不同级别,可以实现或多或少的粒度错误 UI。
  • An error.js boundary will not handle errors thrown in a layout.js component in the same segment because the error boundary is nested inside that layouts component.
  • error.js 边界不会处理同一段中 layout.js 组件中抛出的错误,因为错误边界嵌套在该布局组件内。

Handling Errors in Layouts

处理布局中的错误

error.js boundaries do not catch errors thrown in layout.js or template.js components of the same segment. This intentional hierarchy keeps important UI that is shared between sibling routes (such as navigation) visible and functional when an error occurs.

error.js 边界不会捕获在同一段的 layout.js 或 template.js 组件中抛出的错误。当发生错误时,这种有意的层次结构使兄弟路由(例如导航)之间共享的重要 UI 保持可见和正常运行。

To handle errors within a specific layout or template, place an error.js file in the layouts parent segment.

要处理特定布局或模板中的错误,请将 error.js 文件放在布局父段中。

To handle errors within the root layout or template, use a variation of error.js called global-error.js.

要处理根布局或模板中的错误,请使用称为 global-error.js 的 error.js 变体。

Handling Errors in Root Layouts

处理根布局中的错误

The root app/error.js boundary does not catch errors thrown in the root app/layout.js or app/template.js component.

根 app/error.js 边界不会捕获根 app/layout.js 或 app/template.js 组件中抛出的错误。

To specifically handle errors in these root components, use a variation of error.js called app/global-error.js located in the root app directory.

要专门处理这些根组件中的错误,请使用位于应用程序根目录中的名为 app/global-error.js 的 error.js 变体。

Unlike the root error.js, the global-error.js error boundary wraps the entire application, and its fallback component replaces the root layout when active. Because of this, it is important to note that global-error.jsmust define its own <html> and <body> tags.

与根 error.js 不同,global-error.js 错误边界包裹了整个应用程序,其回退组件在活动时替换根布局。因此,请务必注意 global-error.js 必须定义自己的  和  标签。

global-error.js is the least granular error UI and can be considered "catch-all" error handling for the whole application. It is unlikely to be triggered often as root components are typically less dynamic, and other error.js boundaries will catch most errors.

global-error.js 是最小粒度的错误 UI,可以被认为是整个应用程序的“包罗万象”的错误处理。它不太可能经常被触发,因为根组件通常不太动态,并且其他 error.js 边界会捕获大多数错误。

Even if a global-error.js is defined, it is still recommended to define a root error.js whose fallback component will be rendered within the root layout, which includes globally shared UI and branding.

即使定义了 global-error.js,仍然建议定义一个根 error.js,其回退组件将在根布局中呈现,其中包括全局共享的 UI 和品牌。

app/global-error.tsx

'use client';
export default function GlobalError({
  error,
  reset,
}: {
  error: Error;
  reset: () => void;
}) {
  return (
    <html>
      <body>
        <h2>Something went wrong!</h2>
        <button onClick={() => reset()}>Try again</button>
      </body>
    </html>
  );
}

Handling Server Errors

处理服务器错误

If an error is thrown during data fetching or inside a Server Component, Next.js will forward the resulting Error object to the nearest error.js file as the error prop.

如果在数据获取期间或服务器组件内部抛出错误,Next.js 会将生成的 Error 对象作为错误 prop 转发到最近的 error.js 文件。

When running next dev, the error will be serialized and forwarded from the Server Component to the client error.js. To ensure security when running next start in production, a generic error message is forwarded to error along with a .digest which contains a hash of the error message. This hash can be used to correspond to server logs.

运行 next dev 时,错误将被序列化并从服务器组件转发到客户端 error.js。为确保在生产中运行 next start 时的安全性,一般错误消息将与包含错误消息哈希的 .digest 一起转发给 error。此哈希可用于对应于服务器日志。

目录
相关文章
|
16小时前
uni-app 65egg.js聊天类chat.js封装(二)
uni-app 65egg.js聊天类chat.js封装(二)
29 1
|
16小时前
|
JavaScript
uni-app中关于格式化时间的js文件
uni-app中关于格式化时间的js文件
37 0
|
16小时前
|
开发框架 移动开发 JavaScript
uni-app 68 egg.js发送消息接口开发-单聊(一)
uni-app 68 egg.js发送消息接口开发-单聊(一)
|
16小时前
|
移动开发 JavaScript 前端开发
uni-app和Vue.js二者之间有什么区别?
1. uni-app是一个使用Vue.js开发所有前端应用的框架,支持一次编译多端运行。开发者编写的基础代码只需进行一次编写,就可以发布到多个平台,包括App、H5、微信小程序等。 2. Vue.js是一个渐进式JavaScript框架,用于构建用户界面。与其他大型框架不同的是,Vue被设计为可以自底向上逐层应用。
5 0
|
16小时前
uni-app 68 egg.js发送消息接口开发-单聊(一)
uni-app 68 egg.js发送消息接口开发-单聊(一)
27 7
|
16小时前
uni-app 66聊天类chat.js封装(三)
uni-app 66聊天类chat.js封装(三)
33 6
|
16小时前
uni-app 64聊天类chat.js封装(一)
uni-app 64聊天类chat.js封装(一)
28 2
|
16小时前
uni-app 63egg.js后端用户上线和下线深度剖析
uni-app 63egg.js后端用户上线和下线深度剖析
16 1
|
16小时前
|
中间件 API 数据库
uni-app 24egg.js 基础课
uni-app 24egg.js 基础课
31 0
|
16小时前
|
开发框架 JavaScript 前端开发
深入探讨Vue.js核心技术及uni-app跨平台开发实践
深入探讨Vue.js核心技术及uni-app跨平台开发实践
59 0