From f2cecc883eb8f6c5520c6b3c57ad14b512e52a7f Mon Sep 17 00:00:00 2001 From: xiaoyu2er Date: Wed, 21 May 2025 19:25:28 +0000 Subject: [PATCH] docs: update documentation translations --- .../01-getting-started/01-installation.mdx | 92 +-- .../08-partial-prerendering.mdx | 86 +-- .../01-getting-started/09-fetching-data.mdx | 343 ++++++++++-- .../01-getting-started/11-error-handling.mdx | 68 +-- .../incremental-static-regeneration.mdx | 121 ++-- .../zh-hans/docs/01-app/02-guides/index.mdx | 30 +- .../01-app/02-guides/internationalization.mdx | 38 +- .../migrating/app-router-migration.mdx | 220 ++++---- .../migrating/from-create-react-app.mdx | 128 ++--- .../01-app/02-guides/migrating/from-vite.mdx | 185 ++---- .../01-app/02-guides/production-checklist.mdx | 109 ++-- .../docs/01-app/02-guides/self-hosting.mdx | 106 ++-- .../docs/01-app/02-guides/static-exports.mdx | 94 ++-- .../01-routing/05-error-handling.mdx | 36 +- .../01-routing/13-route-handlers.mdx | 52 +- .../02-data-fetching/01-fetching.mdx | 529 +----------------- .../03-server-actions-and-mutations.mdx | 174 +++--- .../03-file-conventions/error.mdx | 44 +- .../04-functions/generate-metadata.mdx | 172 +++--- .../04-functions/next-request.mdx | 48 +- .../docs/02-pages/02-guides/draft-mode.mdx | 113 ++-- .../incremental-static-regeneration.mdx | 13 +- .../02-guides/internationalization.mdx | 141 +++-- .../docs/02-pages/02-guides/preview-mode.mdx | 58 +- .../01-routing/07-api-routes.mdx | 101 ++-- .../02-rendering/05-client-side-rendering.mdx | 18 +- .../03-data-fetching/01-get-static-props.mdx | 68 +-- .../03-get-server-side-props.mdx | 32 +- .../03-functions/get-static-paths.mdx | 84 +-- .../03-functions/get-static-props.mdx | 64 +-- .../13/01-getting-started/01-installation.mdx | 194 +++++++ .../02-project-structure.mdx | 151 +++++ .../docs/13/01-getting-started/index.mdx | 6 + .../01-building-your-application/index.mdx | 24 + .../02-api-reference/06-create-next-app.mdx | 132 +++++ .../13/02-app/02-api-reference/07-edge.mdx | 166 ++++++ .../02-app/02-api-reference/08-next-cli.mdx | 176 ++++++ .../docs/13/02-app/02-api-reference/index.mdx | 8 + .../content/zh-hans/docs/13/02-app/index.mdx | 72 +++ .../01-building-your-application/index.mdx | 9 + .../02-api-reference/04-create-next-app.mdx | 9 + .../03-pages/02-api-reference/05-next-cli.mdx | 9 + .../13/03-pages/02-api-reference/06-edge.mdx | 9 + .../13/03-pages/02-api-reference/index.mdx | 6 + .../zh-hans/docs/13/03-pages/index.mdx | 10 + .../docs/13/04-architecture/accessibility.mdx | 36 ++ .../docs/13/04-architecture/fast-refresh.mdx | 65 +++ .../zh-hans/docs/13/04-architecture/index.mdx | 8 + .../13/04-architecture/nextjs-compiler.mdx | 305 ++++++++++ .../13/04-architecture/supported-browsers.mdx | 72 +++ .../docs/13/04-architecture/turbopack.mdx | 31 + .../13/05-community/01-contribution-guide.mdx | 410 ++++++++++++++ .../zh-hans/docs/13/05-community/index.mdx | 33 ++ .../14/01-getting-started/01-installation.mdx | 196 +++++++ .../02-project-structure.mdx | 169 ++++++ .../01-building-your-application/index.mdx | 24 + .../14/02-app/02-api-reference/07-edge.mdx | 166 ++++++ .../docs/14/02-app/02-api-reference/index.mdx | 8 + .../01-building-your-application/index.mdx | 9 + .../02-functions/use-report-web-vitals.mdx | 9 + .../02-functions/use-router.mdx | 516 +++++++++++++++++ .../02-functions/userAgent.mdx | 9 + .../03-next-config-js/assetPrefix.mdx | 9 + .../03-next-config-js/basePath.mdx | 9 + .../03-next-config-js/compress.mdx | 9 + .../03-next-config-js/crossOrigin.mdx | 9 + .../03-next-config-js/devIndicators.mdx | 9 + .../03-next-config-js/distDir.mdx | 9 + .../03-next-config-js/env.mdx | 9 + .../03-next-config-js/eslint.mdx | 9 + .../03-next-config-js/exportPathMap.mdx | 9 + .../03-next-config-js/generateBuildId.mdx | 9 + .../03-next-config-js/generateEtags.mdx | 9 + .../03-next-config-js/headers.mdx | 9 + .../03-next-config-js/httpAgentOptions.mdx | 9 + .../03-next-config-js/images.mdx | 9 + .../03-next-config-js/index.mdx | 9 + .../03-next-config-js/instrumentationHook.mdx | 9 + .../03-next-config-js/onDemandEntries.mdx | 9 + .../optimizePackageImports.mdx | 9 + .../03-next-config-js/output.mdx | 9 + .../03-next-config-js/pageExtensions.mdx | 9 + .../03-next-config-js/poweredByHeader.mdx | 9 + .../productionBrowserSourceMaps.mdx | 9 + .../03-next-config-js/reactStrictMode.mdx | 9 + .../03-next-config-js/redirects.mdx | 9 + .../03-next-config-js/rewrites.mdx | 9 + .../runtime-configuration.mdx | 62 ++ .../03-next-config-js/trailingSlash.mdx | 9 + .../03-next-config-js/transpilePackages.mdx | 9 + .../03-next-config-js/turbo.mdx | 10 + .../03-next-config-js/typescript.mdx | 9 + .../03-next-config-js/urlImports.mdx | 9 + .../webVitalsAttribution.mdx | 9 + .../03-next-config-js/webpack.mdx | 10 + .../14/03-pages/02-api-reference/05-edge.mdx | 9 + .../06-cli/create-next-app.mdx | 9 + .../02-api-reference/06-cli/index.mdx | 9 + .../03-pages/02-api-reference/06-cli/next.mdx | 9 + .../14/03-pages/02-api-reference/index.mdx | 6 + 100 files changed, 4970 insertions(+), 1838 deletions(-) create mode 100644 apps/docs/content/zh-hans/docs/13/01-getting-started/01-installation.mdx create mode 100644 apps/docs/content/zh-hans/docs/13/01-getting-started/02-project-structure.mdx create mode 100644 apps/docs/content/zh-hans/docs/13/01-getting-started/index.mdx create mode 100644 apps/docs/content/zh-hans/docs/13/02-app/01-building-your-application/index.mdx create mode 100644 apps/docs/content/zh-hans/docs/13/02-app/02-api-reference/06-create-next-app.mdx create mode 100644 apps/docs/content/zh-hans/docs/13/02-app/02-api-reference/07-edge.mdx create mode 100644 apps/docs/content/zh-hans/docs/13/02-app/02-api-reference/08-next-cli.mdx create mode 100644 apps/docs/content/zh-hans/docs/13/02-app/02-api-reference/index.mdx create mode 100644 apps/docs/content/zh-hans/docs/13/02-app/index.mdx create mode 100644 apps/docs/content/zh-hans/docs/13/03-pages/01-building-your-application/index.mdx create mode 100644 apps/docs/content/zh-hans/docs/13/03-pages/02-api-reference/04-create-next-app.mdx create mode 100644 apps/docs/content/zh-hans/docs/13/03-pages/02-api-reference/05-next-cli.mdx create mode 100644 apps/docs/content/zh-hans/docs/13/03-pages/02-api-reference/06-edge.mdx create mode 100644 apps/docs/content/zh-hans/docs/13/03-pages/02-api-reference/index.mdx create mode 100644 apps/docs/content/zh-hans/docs/13/03-pages/index.mdx create mode 100644 apps/docs/content/zh-hans/docs/13/04-architecture/accessibility.mdx create mode 100644 apps/docs/content/zh-hans/docs/13/04-architecture/fast-refresh.mdx create mode 100644 apps/docs/content/zh-hans/docs/13/04-architecture/index.mdx create mode 100644 apps/docs/content/zh-hans/docs/13/04-architecture/nextjs-compiler.mdx create mode 100644 apps/docs/content/zh-hans/docs/13/04-architecture/supported-browsers.mdx create mode 100644 apps/docs/content/zh-hans/docs/13/04-architecture/turbopack.mdx create mode 100644 apps/docs/content/zh-hans/docs/13/05-community/01-contribution-guide.mdx create mode 100644 apps/docs/content/zh-hans/docs/13/05-community/index.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/01-getting-started/01-installation.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/01-getting-started/02-project-structure.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/02-app/01-building-your-application/index.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/02-app/02-api-reference/07-edge.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/02-app/02-api-reference/index.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/01-building-your-application/index.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/02-functions/use-report-web-vitals.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/02-functions/use-router.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/02-functions/userAgent.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/assetPrefix.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/basePath.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/compress.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/crossOrigin.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/devIndicators.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/distDir.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/env.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/eslint.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/exportPathMap.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/generateBuildId.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/generateEtags.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/headers.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/httpAgentOptions.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/images.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/index.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/instrumentationHook.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/onDemandEntries.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/optimizePackageImports.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/output.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/pageExtensions.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/poweredByHeader.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/productionBrowserSourceMaps.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/reactStrictMode.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/redirects.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/rewrites.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/runtime-configuration.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/trailingSlash.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/transpilePackages.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/turbo.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/typescript.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/urlImports.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/webVitalsAttribution.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/03-next-config-js/webpack.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/05-edge.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/06-cli/create-next-app.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/06-cli/index.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/06-cli/next.mdx create mode 100644 apps/docs/content/zh-hans/docs/14/03-pages/02-api-reference/index.mdx diff --git a/apps/docs/content/zh-hans/docs/01-app/01-getting-started/01-installation.mdx b/apps/docs/content/zh-hans/docs/01-app/01-getting-started/01-installation.mdx index 8af0dbae..affe04e2 100644 --- a/apps/docs/content/zh-hans/docs/01-app/01-getting-started/01-installation.mdx +++ b/apps/docs/content/zh-hans/docs/01-app/01-getting-started/01-installation.mdx @@ -1,23 +1,23 @@ --- -source-updated-at: '2025-05-16T04:52:11.000Z' -translation-updated-at: '2025-05-17T02:12:53.432Z' +source-updated-at: 2025-05-21T18:33:43.000Z +translation-updated-at: 2025-05-21T19:18:02.138Z title: 如何新建 Next.js 项目 nav_title: 安装指南 description: 使用 `create-next-app` CLI 创建新的 Next.js 应用,并配置 TypeScript、ESLint 和模块路径别名。 --- -{/* 本文档内容在应用路由和页面路由间共享。可使用 `内容` 组件添加仅适用于页面路由的内容。任何共享内容不应包裹在组件中。*/} +{/* 本文档内容在应用路由和页面路由间共享。如需添加仅适用于页面路由的内容,可使用 `内容` 组件。共享内容不应包裹在任何组件中。*/} ## 系统要求 开始前请确保系统满足以下要求: - [Node.js 18.18](https://nodejs.org/) 或更高版本 -- macOS、Windows(含 WSL)或 Linux +- macOS、Windows(含 WSL)或 Linux 系统 ## 自动安装 -创建 Next.js 应用最快的方式是使用 [`create-next-app`](/docs/app/api-reference/cli/create-next-app),它会自动完成所有设置。运行以下命令创建项目: +创建 Next.js 应用最快的方式是使用 [`create-next-app`](/docs/app/api-reference/cli/create-next-app),它会自动完成所有配置。运行以下命令创建项目: ```bash filename="终端" npx create-next-app@latest @@ -26,18 +26,18 @@ npx create-next-app@latest 安装过程中会看到以下提示: ```txt filename="终端" -项目名称是什么?my-app +请输入项目名称?my-app 是否使用 TypeScript?否 / 是 是否使用 ESLint?否 / 是 是否使用 Tailwind CSS?否 / 是 -是否将代码放在 `src/` 目录中?否 / 是 -是否使用 App Router?(推荐)否 / 是 +是否将代码放在 `src/` 目录下?否 / 是 +是否使用应用路由(推荐)?否 / 是 是否在 `next dev` 中使用 Turbopack?否 / 是 是否自定义导入别名(默认为 `@/*`)?否 / 是 -要配置什么导入别名?@/* +请输入配置的导入别名?@/* ``` -完成提示后,[`create-next-app`](/docs/app/api-reference/cli/create-next-app) 会创建以项目名命名的文件夹并安装所需依赖。 +完成提示后,[`create-next-app`](/docs/app/api-reference/cli/create-next-app) 会创建项目文件夹并安装所需依赖。 ## 手动安装 @@ -65,7 +65,7 @@ npm install next@latest react@latest react-dom@latest - `next dev`:启动开发服务器 - `next build`:构建生产环境应用 - `next start`:启动生产服务器 -- `next lint`:运行 ESLint +- `next lint`:运行 ESLint 检查 @@ -103,20 +103,20 @@ export default function RootLayout({ children }) { ```tsx filename="app/page.tsx" switcher export default function Page() { - return

Hello, Next.js!

+ return

你好,Next.js!

} ``` ```jsx filename="app/page.js" switcher export default function Page() { - return

Hello, Next.js!

+ return

你好,Next.js!

} ``` -当用户访问应用根路径 (`/`) 时,`layout.tsx` 和 `page.tsx` 会被渲染。 +当用户访问应用根路径 (`/`) 时,`layout.tsx` 和 `page.tsx` 将同时渲染。 App 文件夹结构 **须知**: > -> - 如果忘记创建根布局,运行 `next dev` 启动开发服务器时 Next.js 会自动创建该文件 -> - 可选择在项目根目录使用 [`src` 文件夹](/docs/app/api-reference/file-conventions/src-folder) 来分离应用代码和配置文件 +> - 如果忘记创建根布局,运行 `next dev` 启动开发服务器时 Next.js 会自动生成 +> - 可选择使用项目根目录下的 [`src` 文件夹](/docs/app/api-reference/file-conventions/src-folder) 来分离应用代码和配置文件
@@ -136,21 +136,21 @@ export default function Page() { Next.js 使用文件系统路由,意味着应用路由由文件结构决定。 -在项目根目录创建 `pages` 文件夹,然后添加 `index.tsx` 文件作为首页 (`/`): +在项目根目录创建 `pages` 文件夹,然后添加 `index.tsx` 作为首页 (`/`): ```tsx filename="pages/index.tsx" switcher export default function Page() { - return

Hello, Next.js!

+ return

你好,Next.js!

} ``` ```jsx filename="pages/index.js" switcher export default function Page() { - return

Hello, Next.js!

+ return

你好,Next.js!

} ``` -接着在 `pages/` 中添加 `_app.tsx` 文件定义全局布局。了解更多关于[自定义 App 文件](/docs/pages/building-your-application/routing/custom-app)。 +接着在 `pages/` 下添加 `_app.tsx` 定义全局布局。了解更多关于[自定义 App 文件](/docs/pages/building-your-application/routing/custom-app)。 ```tsx filename="pages/_app.tsx" switcher import type { AppProps } from 'next/app' @@ -166,7 +166,7 @@ export default function App({ Component, pageProps }) { } ``` -最后在 `pages/` 中添加 `_document.tsx` 文件控制服务器初始响应。了解更多关于[自定义 Document 文件](/docs/pages/building-your-application/routing/custom-document)。 +最后在 `pages/` 下添加 `_document.tsx` 控制服务器初始响应。了解更多关于[自定义 Document 文件](/docs/pages/building-your-application/routing/custom-document)。 ```tsx filename="pages/_document.tsx" switcher import { Html, Head, Main, NextScript } from 'next/document' @@ -204,7 +204,7 @@ export default function Document() { ### 创建 `public` 文件夹(可选) -在项目根目录创建 [`public` 文件夹](/docs/app/api-reference/file-conventions/public-folder) 存放图片、字体等静态资源。`public` 内的文件可通过根路径 (`/`) 引用。 +在项目根目录创建 [`public` 文件夹](/docs/app/api-reference/file-conventions/public-folder) 存放静态资源(如图片、字体等)。`public` 中的文件可通过根路径 (`/`) 引用。 例如 `public/profile.png` 可引用为 `/profile.png`: @@ -212,7 +212,7 @@ export default function Document() { import Image from 'next/image' export default function Page() { - return Profile + return 个人头像 } ``` @@ -220,33 +220,33 @@ export default function Page() { import Image from 'next/image' export default function Page() { - return Profile + return 个人头像 } ``` ## 运行开发服务器 -1. 运行 `npm run dev` 启动开发服务器 +1. 执行 `npm run dev` 启动开发服务器 2. 访问 `http://localhost:3000` 查看应用 -3. 编辑`app/page.tsx` `pages/index.tsx` 文件并保存,浏览器中即可看到更新结果 +3. 编辑 `app/page.tsx``pages/index.tsx` 文件并保存,浏览器中即可看到更新结果 ## 配置 TypeScript -> 最低 TypeScript 版本要求:`v4.5.2` +> TypeScript 最低版本要求:`v4.5.2` -Next.js 内置 TypeScript 支持。要添加 TypeScript 到项目,只需将文件重命名为 `.ts` / `.tsx` 并运行 `next dev`。Next.js 会自动安装必要依赖并添加包含推荐配置的 `tsconfig.json` 文件。 +Next.js 内置 TypeScript 支持。要将 TypeScript 添加到项目,只需将文件重命名为 `.ts`/`.tsx` 并运行 `next dev`。Next.js 会自动安装必要依赖并创建包含推荐配置的 `tsconfig.json` 文件。 ### IDE 插件 -Next.js 包含自定义 TypeScript 插件和类型检查器,可供 VSCode 等代码编辑器实现高级类型检查和自动补全。 +Next.js 包含自定义 TypeScript 插件和类型检查器,可供 VSCode 等编辑器实现高级类型检查和自动补全。 在 VS Code 中启用插件: 1. 打开命令面板 (`Ctrl/⌘` + `Shift` + `P`) -2. 搜索 "TypeScript: Select TypeScript Version" -3. 选择 "Use Workspace Version" +2. 搜索 "TypeScript: 选择 TypeScript 版本" +3. 选择 "使用工作区版本" TypeScript 命令面板 -更多信息请参考 [TypeScript 参考文档](/docs/app/api-reference/config/next-config-js/typescript)。 +更多信息请参考 [TypeScript 配置文档](/docs/app/api-reference/config/next-config-js/typescript)。 ## 配置 ESLint -Next.js 内置 ESLint 支持。使用 `create-next-app` 创建新项目时会自动安装必要包并配置正确设置。 +Next.js 内置 ESLint 支持。使用 `create-next-app` 创建项目时会自动安装必要包并配置正确设置。 -要为现有项目手动添加 ESLint,在 `package.json` 中添加 `next lint` 脚本: +要为现有项目手动添加 ESLint,请在 `package.json` 中添加 `next lint` 脚本: ```json filename="package.json" { @@ -274,35 +274,35 @@ Next.js 内置 ESLint 支持。使用 `create-next-app` 创建新项目时会自 } ``` -然后运行 `npm run lint`,将引导完成安装和配置流程: +然后运行 `npm run lint`,安装向导将引导完成配置过程: ```bash filename="终端" npm run lint ``` -您会看到如下提示: +您将看到如下提示: -> ? 您希望如何配置 ESLint? +> ? 希望如何配置 ESLint? > > ❯ 严格模式(推荐) > 基础模式 > 取消 -- **严格模式**:包含 Next.js 基础 ESLint 配置及更严格的 Core Web Vitals 规则集。初次设置 ESLint 时推荐此配置 +- **严格模式**:包含 Next.js 基础 ESLint 配置及更严格的 Core Web Vitals 规则集。首次配置 ESLint 时推荐使用 - **基础模式**:仅包含 Next.js 基础 ESLint 配置 -- **取消**:跳过配置。如计划自定义 ESLint 配置请选此项 +- **取消**:跳过配置。如需自定义 ESLint 配置请选择此项 选择"严格"或"基础"后,Next.js 会自动安装 `eslint` 和 `eslint-config-next` 依赖,并在项目根目录创建包含所选配置的 `.eslintrc.json` 文件。 -现在可随时运行 `next lint` 执行 ESLint 检查。ESLint 设置完成后,每次构建 (`next build`) 时也会自动运行。错误会导致构建失败,而警告不会。 +此后可通过运行 `next lint` 执行 ESLint 检查。ESLint 配置完成后,每次构建 (`next build`) 时也会自动运行。错误会导致构建失败,而警告不会。 更多信息请参考 [ESLint 插件文档](/docs/app/api-reference/config/next-config-js/eslint)。 ## 配置绝对导入和模块路径别名 -Next.js 原生支持 `tsconfig.json` 和 `jsconfig.json` 文件中的 `"paths"` 和 `"baseUrl"` 选项。 +Next.js 原生支持 `tsconfig.json` 和 `jsconfig.json` 中的 `"paths"` 和 `"baseUrl"` 选项。 -这些选项允许将项目目录别名化为绝对路径,使模块导入更简洁。例如: +这些选项允许将项目目录映射为绝对路径,使模块导入更清晰简洁。例如: ```jsx // 之前 @@ -312,7 +312,7 @@ import { Button } from '../../../components/button' import { Button } from '@/components/button' ``` -要配置绝对导入,在 `tsconfig.json` 或 `jsconfig.json` 中添加 `baseUrl` 配置选项。例如: +要配置绝对导入,请在 `tsconfig.json` 或 `jsconfig.json` 中添加 `baseUrl` 配置: ```json filename="tsconfig.json 或 jsconfig.json" { @@ -322,7 +322,7 @@ import { Button } from '@/components/button' } ``` -除配置 `baseUrl` 路径外,还可使用 `"paths"` 选项设置模块路径"别名"。 +除配置 `baseUrl` 外,还可使用 `"paths"` 选项设置模块路径"别名"。 例如以下配置将 `@/components/*` 映射到 `components/*`: @@ -338,4 +338,4 @@ import { Button } from '@/components/button' } ``` -每个 `"paths"` 都相对于 `baseUrl` 位置。 +每个 `"paths"` 都相对于 `baseUrl` 指定的位置。 \ No newline at end of file diff --git a/apps/docs/content/zh-hans/docs/01-app/01-getting-started/08-partial-prerendering.mdx b/apps/docs/content/zh-hans/docs/01-app/01-getting-started/08-partial-prerendering.mdx index 6580dd42..1320461f 100644 --- a/apps/docs/content/zh-hans/docs/01-app/01-getting-started/08-partial-prerendering.mdx +++ b/apps/docs/content/zh-hans/docs/01-app/01-getting-started/08-partial-prerendering.mdx @@ -1,21 +1,21 @@ --- -source-updated-at: 2025-05-19T22:31:51.000Z -translation-updated-at: 2025-05-19T23:06:15.558Z +source-updated-at: 2025-05-21T18:33:43.000Z +translation-updated-at: 2025-05-21T19:17:34.430Z title: 如何使用部分预渲染 (Partial Prerendering) -nav_title: 部分预渲染 (PPR) -description: 学习如何通过部分预渲染 (Partial Prerendering) 结合静态渲染与动态渲染的优势。 +nav_title: 部分预渲染 +description: 了解如何通过部分预渲染 (Partial Prerendering) 结合静态渲染与动态渲染的优势。 version: experimental related: title: 后续步骤 - description: 了解更多关于部分预渲染 (PPR) 的配置选项。 + description: 深入了解部分预渲染 (Partial Prerendering) 的配置选项。 links: - app/api-reference/config/next-config-js/ppr --- -部分预渲染 (Partial Prerendering, PPR) 是一种渲染策略,允许你在同一路由中结合静态与动态内容。这既能提升初始页面性能,又能支持个性化的动态数据。 +部分预渲染 (PPR) 是一种渲染策略,允许您在同一路由中结合静态与动态内容。这种方式既提升了初始页面性能,又能支持个性化动态数据。 部分预渲染的产品页面展示静态导航栏和产品信息,以及动态购物车和推荐商品 **🎥 观看视频:** 为什么需要 PPR 及其工作原理 → [YouTube (10 分钟)](https://www.youtube.com/watch?v=MTcPrTIBkpA)。 +> **🎥 观看视频:** PPR 的原理与价值 → [YouTube (10分钟)](https://www.youtube.com/watch?v=MTcPrTIBkpA) ## 部分预渲染如何工作? -要理解部分预渲染,需要先熟悉 Next.js 提供的渲染策略。 +理解部分预渲染前,需要先熟悉 Next.js 提供的渲染策略。 -### 静态渲染 (Static Rendering) +### 静态渲染 -静态渲染会提前生成 HTML —— 可以在构建时或通过 [重新验证 (revalidation)](/docs/app/building-your-application/data-fetching/incremental-static-regeneration) 完成。结果会被缓存并在用户和请求间共享。 +静态渲染会提前生成 HTML——在构建时或通过 [重新验证](/docs/app/guides/incremental-static-regeneration) 完成。结果会被缓存并在用户和请求间共享。 -在部分预渲染中,Next.js 会为路由预渲染一个 **静态外壳 (static shell)**,包含布局和任何不依赖请求时数据的组件。 +在部分预渲染中,Next.js 会为路由预渲染一个 **静态外壳**,可包含布局和任何不依赖请求时数据的组件。 -### 动态渲染 (Dynamic Rendering) +### 动态渲染 -动态渲染会在 **请求时 (request time)** 生成 HTML,从而根据请求时的数据提供个性化内容。 +动态渲染会在 **请求时** 生成 HTML,使您能基于请求时数据提供个性化内容。 -组件在以下情况下会变为动态: +组件在以下情况会变为动态: - 使用 [`cookies`](/docs/app/api-reference/functions/cookies) - 使用 [`headers`](/docs/app/api-reference/functions/headers) @@ -52,19 +52,19 @@ related: - 使用 [`draftMode`](/docs/app/api-reference/functions/draft-mode) - 使用 [`searchParams` 属性](/docs/app/api-reference/file-conventions/page#searchparams-optional) - 使用 [`unstable_noStore`](/docs/app/api-reference/functions/unstable_noStore) -- 使用 `{ cache: 'no-store' }` 的 [`fetch`](/docs/app/api-reference/functions/fetch) +- 使用 [`fetch`](/docs/app/api-reference/functions/fetch) 并设置 `{ cache: 'no-store' }` -在部分预渲染中,使用这些 API 会抛出特殊的 React 错误,提示 Next.js 该组件无法静态渲染,导致构建错误。你可以使用 [Suspense](#suspense) 将渲染推迟到运行时。 +在部分预渲染中,使用这些 API 会抛出特殊 React 错误,提示 Next.js 该组件无法静态渲染,导致构建错误。您可以使用 [Suspense](#suspense) 延迟渲染至运行时。 ### Suspense -React 的 [Suspense](https://react.dev/reference/react/Suspense) 用于延迟渲染部分应用,直到满足某些条件。 +React 的 [Suspense](https://react.dev/reference/react/Suspense) 用于延迟渲染部分应用直到满足特定条件。 -在部分预渲染中,Suspense 用于标记组件树中的 **动态边界 (dynamic boundaries)**。 +在部分预渲染中,Suspense 用于标记组件树中的 **动态边界**。 -构建时,Next.js 会预渲染静态内容和 `fallback` UI。动态内容会 **推迟 (postponed)** 到用户请求路由时加载。 +构建时,Next.js 会预渲染静态内容和 `fallback` UI。动态内容会 **延迟** 至用户请求路由时加载。 -用 Suspense 包裹组件不会使组件本身变为动态(动态性由 API 使用决定),而是作为封装动态内容的边界,并启用 [流式传输 (streaming)](#streaming)。 +用 Suspense 包裹组件不会使组件本身变为动态(动态性由 API 使用决定),而是作为封装动态内容的边界,实现 [流式传输](#streaming) ```jsx filename="app/page.js" import { Suspense } from 'react' @@ -86,33 +86,33 @@ export default function Page() { } ``` -### 流式传输 (Streaming) +### 流式传输 -流式传输将路由拆分为多个块,并在准备就绪时逐步传输到客户端。这样用户可以在整个内容完成渲染前立即看到部分页面。 +流式传输将路由拆分为多个块,并在准备就绪时逐步流式传输至客户端。这使得用户能在全部内容完成渲染前立即看到部分页面。 图表展示客户端部分渲染的页面,以及正在流式传输的区块加载 UI。 -在部分预渲染中,包裹在 Suspense 中的动态组件会从服务器并行流式传输。 +在部分预渲染中,包裹在 Suspense 中的动态组件会从服务器并行开始流式传输。 图表展示流式传输期间路由段的并行化,显示各个区块的数据获取、渲染和水合。 -为了减少网络开销,完整响应(包括静态 HTML 和流式传输的动态部分)会在 **单个 HTTP 请求** 中发送。这避免了额外的往返,提升了初始加载和整体性能。 +为减少网络开销,完整响应(包括静态 HTML 和流式动态部分)会通过 **单次 HTTP 请求** 发送。这避免了额外往返,提升了初始加载和整体性能。 ## 启用部分预渲染 -你可以通过在 `next.config.ts` 文件中添加 [`ppr`](https://rc.nextjs.org/docs/app/api-reference/next-config-js/ppr) 选项来启用 PPR: +您可以通过在 `next.config.ts` 文件中添加 [`ppr`](https://rc.nextjs.org/docs/app/api-reference/next-config-js/ppr) 选项来启用 PPR: ```ts filename="next.config.ts" highlight={5} switcher import type { NextConfig } from 'next' @@ -135,7 +135,7 @@ const nextConfig = { } ``` -`'incremental'` 值允许你为特定路由启用 PPR: +`'incremental'` 值允许您为特定路由启用 PPR: ```tsx filename="/app/dashboard/layout.tsx" export const experimental_ppr = true @@ -153,18 +153,18 @@ export default function Layout({ children }) { } ``` -未设置 `experimental_ppr` 的路由会默认为 `false`,不会使用 PPR 预渲染。你需要为每个路由显式启用 PPR。 +未设置 `experimental_ppr` 的路由默认为 `false`,不会使用 PPR 预渲染。您需要为每个路由显式启用 PPR。 > **须知:** > -> - `experimental_ppr` 会应用到路由段的所有子节点,包括嵌套布局和页面。你无需在每个文件中添加,只需在路由的顶层段设置。 -> - 要为子段禁用 PPR,可以在子段中将 `experimental_ppr` 设为 `false`。 +> - `experimental_ppr` 会应用于路由段的所有子级,包括嵌套布局和页面。您无需在每个文件中添加,只需在路由的顶层段设置。 +> - 要为子段禁用 PPR,可在子段中将 `experimental_ppr` 设为 `false`。 ## 示例 ### 动态 API -当使用需要查看请求的动态 API 时,Next.js 会为该路由启用动态渲染。要继续使用 PPR,请用 Suspense 包裹组件。例如,`` 组件因使用 `cookies` API 而变为动态: +当使用需要查看传入请求的动态 API 时,Next.js 会为该路由启用动态渲染。要继续使用 PPR,请用 Suspense 包裹组件。例如,`` 组件因使用 `cookies` API 而变为动态: ```jsx filename="app/user.js" switcher import { cookies } from 'next/headers' @@ -184,7 +184,7 @@ export async function User() { } ``` -`` 组件会流式传输,而 `` 中的其他内容会被预渲染并成为静态外壳的一部分。 +`` 组件将被流式传输,而 `` 中的其他内容会被预渲染并成为静态外壳的一部分。 ```tsx filename="app/page.tsx" switcher import { Suspense } from 'react' @@ -195,7 +195,7 @@ export const experimental_ppr = true export default function Page() { return (
-

这部分会被预渲染

+

这部分内容将被预渲染

}> @@ -213,7 +213,7 @@ export const experimental_ppr = true export default function Page() { return (
-

这部分会被预渲染

+

这部分内容将被预渲染

}> @@ -224,7 +224,7 @@ export default function Page() { ### 传递动态属性 -组件仅在访问值时才会启用动态渲染。例如,如果你从 `` 组件读取 `searchParams`,可以将其作为属性传递给其他组件: +只有在访问值时组件才会启用动态渲染。例如,如果您从 `` 组件读取 `searchParams`,可以将其作为属性传递给其他组件: ```tsx filename="app/page.tsx" switcher import { Table, TableSkeleton } from './table' @@ -237,7 +237,7 @@ export default function Page({ }) { return (
-

这部分会被预渲染

+

这部分内容将被预渲染

}> @@ -253,7 +253,7 @@ import { Suspense } from 'react' export default function Page({ searchParams }) { return (
-

这部分会被预渲染

+

这部分内容将被预渲染

}>
@@ -262,7 +262,7 @@ export default function Page({ searchParams }) { } ``` -在表格组件内部,访问 `searchParams` 的值会使该组件变为动态,而页面的其余部分会被预渲染。 +在表格组件内部,访问 `searchParams` 的值会使该组件变为动态,而页面其余部分会被预渲染。 ```tsx filename="app/table.tsx" switcher export async function Table({ diff --git a/apps/docs/content/zh-hans/docs/01-app/01-getting-started/09-fetching-data.mdx b/apps/docs/content/zh-hans/docs/01-app/01-getting-started/09-fetching-data.mdx index 5e75197e..91f0987c 100644 --- a/apps/docs/content/zh-hans/docs/01-app/01-getting-started/09-fetching-data.mdx +++ b/apps/docs/content/zh-hans/docs/01-app/01-getting-started/09-fetching-data.mdx @@ -1,31 +1,33 @@ --- -source-updated-at: 2025-05-19T22:31:51.000Z -translation-updated-at: 2025-05-19T23:06:18.784Z +source-updated-at: 2025-05-21T18:33:43.000Z +translation-updated-at: 2025-05-21T19:19:09.115Z title: 如何获取数据并实现流式传输 nav_title: 数据获取 description: 开始在您的应用中获取数据并流式传输内容。 related: title: API 参考 - description: 通过阅读 API 参考了解更多本页提到的功能。 + description: 通过阅读 API 参考文档了解更多本页提到的功能特性。 links: - app/api-reference/functions/fetch - app/api-reference/file-conventions/loading + - app/api-reference/config/next-config-js/logging + - app/api-reference/config/next-config-js/taint --- -本页将引导您了解如何在 [服务端组件 (Server Components)](#server-components) 和 [客户端组件 (Client Components)](#client-components) 中获取数据,以及如何对依赖数据的内容进行 [流式传输 (streaming)](#streaming)。 +本页将引导您了解如何在 [服务端与客户端组件](/docs/app/getting-started/server-and-client-components) 中获取数据,以及如何流式传输依赖数据的组件。 -## 获取数据 +## 数据获取 ### 服务端组件 -您可以通过以下方式在服务端组件中获取数据: +您可以在服务端组件中通过以下方式获取数据: 1. 使用 [`fetch` API](#with-the-fetch-api) 2. 使用 [ORM 或数据库](#with-an-orm-or-database) #### 使用 `fetch` API -要在服务端组件中使用 `fetch` API 获取数据,将组件转换为异步函数,并等待 `fetch` 调用。例如: +要通过 `fetch` API 获取数据,将您的组件转换为异步函数,并 await `fetch` 调用。例如: ```tsx filename="app/blog/page.tsx" switcher export default async function Page() { @@ -55,9 +57,14 @@ export default async function Page() { } ``` +> **须知:** +> +> - `fetch` 响应默认不会被缓存。但 Next.js 会对路由进行 [预渲染](/docs/app/getting-started/partial-prerendering#static-rendering),输出结果会被缓存以提升性能。如需启用 [动态渲染](/docs/app/getting-started/partial-prerendering#dynamic-rendering),请使用 `{ cache: 'no-store' }` 选项。参阅 [`fetch` API 参考](/docs/app/api-reference/functions/fetch)。 +> - 开发环境下,您可以记录 `fetch` 调用以便更好地调试和观察。参阅 [`logging` API 参考](/docs/app/api-reference/config/next-config-js/logging)。 + #### 使用 ORM 或数据库 -由于服务端组件在服务器端渲染,您可以安全地使用 ORM 或数据库客户端进行查询。将组件转换为异步函数,并等待调用: +由于服务端组件在服务器端渲染,您可以安全地使用 ORM 或数据库客户端进行查询。将组件转换为异步函数,并 await 调用: ```tsx filename="app/blog/page.tsx" switcher import { db, posts } from '@/lib/db' @@ -91,21 +98,21 @@ export default async function Page() { ### 客户端组件 -在客户端组件中获取数据有两种方式: +在客户端组件中有两种获取数据的方式: 1. 使用 React 的 [`use` 钩子](https://react.dev/reference/react/use) 2. 使用社区库如 [SWR](https://swr.vercel.app/) 或 [React Query](https://tanstack.com/query/latest) #### 使用 `use` 钩子流式传输数据 -您可以使用 React 的 [`use` 钩子](https://react.dev/reference/react/use) 将数据从服务器 [流式传输 (streaming)](#streaming) 到客户端。首先在服务端组件中获取数据,然后将 Promise 作为 prop 传递给客户端组件: +您可以使用 React 的 [`use` 钩子](https://react.dev/reference/react/use) 将数据从服务器 [流式传输](#streaming) 到客户端。首先在服务端组件中获取数据,然后将 Promise 作为 prop 传递给客户端组件: ```tsx filename="app/blog/page.tsx" switcher import Posts from '@/app/ui/posts import { Suspense } from 'react' export default function Page() { - // 不要等待数据获取函数 + // 不要 await 数据获取函数 const posts = getPosts() return ( @@ -121,7 +128,7 @@ import Posts from '@/app/ui/posts import { Suspense } from 'react' export default function Page() { - // 不要等待数据获取函数 + // 不要 await 数据获取函数 const posts = getPosts() return ( @@ -132,7 +139,7 @@ export default function Page() { } ``` -然后,在客户端组件中使用 `use` 钩子读取 Promise: +然后在客户端组件中使用 `use` 钩子读取 Promise: ```tsx filename="app/ui/posts.tsx" switcher 'use client' @@ -172,11 +179,11 @@ export default function Posts({ posts }) { } ``` -在上面的示例中,您需要将 `` 组件包裹在 [`` 边界](https://react.dev/reference/react/Suspense) 中。这意味着在 Promise 解析期间将显示 fallback 内容。了解更多关于 [流式传输 (streaming)](#streaming) 的信息。 +在上例中,您需要用 [`` 边界](https://react.dev/reference/react/Suspense) 包裹 `` 组件。这意味着在 Promise 解析期间会显示 fallback UI。了解更多关于 [流式传输](#streaming) 的内容。 #### 社区库 -您可以使用社区库如 [SWR](https://swr.vercel.app/) 或 [React Query](https://tanstack.com/query/latest) 在客户端组件中获取数据。这些库有自己的缓存、流式传输和其他功能的语义。例如,使用 SWR: +您可以使用社区库如 [SWR](https://swr.vercel.app/) 或 [React Query](https://tanstack.com/query/latest) 在客户端组件中获取数据。这些库有自己的缓存、流式传输等特性语义。例如使用 SWR: ```tsx filename="app/blog/page.tsx" switcher 'use client' @@ -205,6 +212,7 @@ export default function BlogPage() { ```jsx filename="app/blog/page.js" switcher 'use client' + import useSWR from 'swr' const fetcher = (url) => fetch(url).then((r) => r.json()) @@ -230,28 +238,28 @@ export default function BlogPage() { ## 流式传输 -> **警告:** 以下内容假设您的应用中启用了 [`dynamicIO` 配置选项](/docs/app/api-reference/config/next-config-js/dynamicIO)。该标志在 Next.js 15 canary 中引入。 +> **警告:** 以下内容假设您的应用已启用 [`dynamicIO` 配置选项](/docs/app/api-reference/config/next-config-js/dynamicIO)。该标志在 Next.js 15 canary 版本中引入。 -在服务端组件中使用 `async/await` 时,Next.js 将选择 **动态渲染 (dynamic rendering)**。这意味着数据将在每次用户请求时在服务器端获取和渲染。如果有任何慢速数据请求,整个路由将被阻塞渲染。 +在服务端组件中使用 `async/await` 时,Next.js 会启用 **动态渲染**。这意味着数据将在每次用户请求时在服务器端获取并渲染。如果有任何慢速数据请求,整个路由的渲染都会被阻塞。 -为了改善初始加载时间和用户体验,您可以使用流式传输将页面的 HTML 拆分为较小的块,并逐步将这些块从服务器发送到客户端。 +为了改善初始加载时间和用户体验,您可以使用流式传输将页面的 HTML 拆分为小块,并逐步从服务器发送到客户端。 -您可以通过以下两种方式在应用中实现流式传输: +有两种方式可以在应用中实现流式传输: 1. 使用 [`loading.js` 文件](#with-loadingjs) 2. 使用 React 的 [`` 组件](#with-suspense) ### 使用 `loading.js` -您可以在页面所在文件夹中创建 `loading.js` 文件,以便在数据获取期间流式传输 **整个页面**。例如,要流式传输 `app/blog/page.js`,请在 `app/blog` 文件夹中添加该文件。 +您可以在页面所在文件夹中创建 `loading.js` 文件,在数据获取期间流式传输 **整个页面**。例如要为 `app/blog/page.js` 添加流式传输,请在 `app/blog` 文件夹中添加该文件。 -在后台,`loading.js` 将被嵌套在 `layout.js` 中,并自动将 `page.js` 文件及其子内容包裹在 `` 边界中。 +在底层,`loading.js` 会被嵌套在 `layout.js` 中,并自动将 `page.js` 文件及其子组件包裹在 `` 边界内。 -这种方法适用于路由段(布局和页面),但对于更细粒度的流式传输,您可以使用 ``。 +这种方法适用于路由段(布局和页面),如需更细粒度的流式传输,可以使用 ``。 ### 使用 `` -`` 允许您更精细地控制页面的哪些部分进行流式传输。例如,您可以立即显示 `` 边界之外的任何页面内容,并流式传输边界内的博客文章列表。 +`` 允许您更精细地控制页面的哪些部分需要流式传输。例如,您可以立即显示 `` 边界外的页面内容,而边界内的博客列表则进行流式传输。 ```tsx filename="app/blog/page.tsx" switcher import { Suspense } from 'react' @@ -309,13 +317,13 @@ import BlogListSkeleton from '@/components/BlogListSkeleton' export default function BlogPage() { return (
- {/* 这部分内容将立即发送到客户端 */} + {/* 这部分内容会立即发送到客户端 */}
-

Welcome to the Blog

-

Read the latest posts below.

+

欢迎来到博客

+

阅读以下最新文章。

- {/* 任何包裹在 边界中的内容将被流式传输 */} + {/* 任何包裹在 边界内的内容都会流式传输 */} }> @@ -333,13 +341,13 @@ import BlogListSkeleton from '@/components/BlogListSkeleton' export default function BlogPage() { return (
- {/* 这部分内容将立即发送到客户端 */} + {/* 这部分内容会立即发送到客户端 */}
-

Welcome to the Blog

-

Read the latest posts below.

+

欢迎来到博客

+

阅读以下最新文章。

- {/* 任何包裹在 边界中的内容将被流式传输 */} + {/* 任何包裹在 边界内的内容都会流式传输 */} }> @@ -351,6 +359,269 @@ export default function BlogPage() { ### 创建有意义的加载状态 -即时加载状态是在导航后立即向用户显示的 fallback UI。为了获得最佳用户体验,我们建议设计有意义的加载状态,帮助用户理解应用正在响应。例如,您可以使用骨架屏和加载动画,或者未来屏幕的一小部分但有意义的内容,如封面照片、标题等。 +即时加载状态是导航后立即向用户显示的 fallback UI。为了最佳用户体验,我们建议设计有意义的加载状态,帮助用户理解应用正在响应。例如可以使用骨架屏和加载动画,或未来屏幕中的一小部分有意义内容如封面图片、标题等。 + +开发时,您可以使用 [React Devtools](https://react.dev/learn/react-developer-tools) 预览和检查组件的加载状态。 + +## 示例 + +### 顺序数据获取 + +顺序数据获取发生在树形结构的嵌套组件各自获取数据且请求未被 [去重](/docs/app/deep-dive/caching#request-memoization) 时,会导致响应时间变长。 + + + +有时您可能需要这种模式,因为某个获取依赖于另一个获取的结果。 + +例如,`` 组件只有在 `` 组件完成数据获取后才会开始获取数据,因为 `` 依赖 `artistID` prop: + +```tsx filename="app/artist/[username]/page.tsx" switcher +export default async function Page({ + params, +}: { + params: Promise<{ username: string }> +}) { + const { username } = await params + // 获取艺术家信息 + const artist = await getArtist(username) + + return ( + <> +

{artist.name}

+ {/* 在 Playlists 组件加载时显示 fallback UI */} + Loading...
}> + {/* 将艺术家 ID 传递给 Playlists 组件 */} + +
+ + ) +} + +async function Playlists({ artistID }: { artistID: string }) { + // 使用艺术家 ID 获取播放列表 + const playlists = await getArtistPlaylists(artistID) + + return ( +
    + {playlists.map((playlist) => ( +
  • {playlist.name}
  • + ))} +
+ ) +} +``` + +```jsx filename="app/artist/[username]/page.js" switcher +export default async function Page({ params }) { + const { username } = await params + // 获取艺术家信息 + const artist = await getArtist(username) + + return ( + <> +

{artist.name}

+ {/* 在 Playlists 组件加载时显示 fallback UI */} + Loading...
}> + {/* 将艺术家 ID 传递给 Playlists 组件 */} + +
+ + ) +} + +async function Playlists({ artistID }) { + // 使用艺术家 ID 获取播放列表 + const playlists = await getArtistPlaylists(artistID) + + return ( +
    + {playlists.map((playlist) => ( +
  • {playlist.name}
  • + ))} +
+ ) +} +``` + +为了改善用户体验,您应该使用 [React ``](/docs/app/building-your-application/routing/loading-ui-and-streaming#streaming-with-suspense) 在数据获取时显示 `fallback`。这将启用 [流式传输](#streaming) 并防止整个路由被顺序数据请求阻塞。 + +### 并行数据获取 + +当路由中的数据请求被主动发起并同时开始时,就会发生并行数据获取。 + +默认情况下,[布局和页面](/docs/app/getting-started/layouts-and-pages)是并行渲染的。因此每个路由段会尽可能早地开始获取数据。 + +然而,在_任何_组件内部,如果将多个 `async`/`await` 请求按顺序放置,它们仍然会串行执行。例如,`getAlbums` 会阻塞直到 `getArtist` 完成解析: + +```tsx filename="app/artist/[username]/page.tsx" switcher +import { getArtist, getAlbums } from '@/app/lib/data' + +export default async function Page({ params }) { + // 这些请求将串行执行 + const { username } = await params + const artist = await getArtist(username) + const albums = await getAlbums(username) + return
{artist.name}
+} +``` + +你可以通过在数据使用组件外部定义请求,并使用 [`Promise.all`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all) 一起解析它们来实现并行请求: + +```tsx filename="app/artist/[username]/page.tsx" highlight={3,8,23} switcher +import Albums from './albums' + +async function getArtist(username: string) { + const res = await fetch(`https://api.example.com/artist/${username}`) + return res.json() +} + +async function getAlbums(username: string) { + const res = await fetch(`https://api.example.com/artist/${username}/albums`) + return res.json() +} + +export default async function Page({ + params, +}: { + params: Promise<{ username: string }> +}) { + const { username } = await params + const artistData = getArtist(username) + const albumsData = getAlbums(username) + + // 并行发起两个请求 + const [artist, albums] = await Promise.all([artistData, albumsData]) + + return ( + <> +

{artist.name}

+ + + ) +} +``` + +```jsx filename="app/artist/[username]/page.js" highlight={3,8,19} switcher +import Albums from './albums' + +async function getArtist(username) { + const res = await fetch(`https://api.example.com/artist/${username}`) + return res.json() +} + +async function getAlbums(username) { + const res = await fetch(`https://api.example.com/artist/${username}/albums`) + return res.json() +} + +export default async function Page({ params }) { + const { username } = await params + const artistData = getArtist(username) + const albumsData = getAlbums(username) + + // 并行发起两个请求 + const [artist, albums] = await Promise.all([artistData, albumsData]) + + return ( + <> +

{artist.name}

+ + + ) +} +``` + +> **须知:** 使用 `Promise.all` 时,如果其中一个请求失败,整个操作都会失败。要处理这种情况,可以使用 [`Promise.allSettled`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled) 方法替代。 + +### 数据预加载 + +你可以通过创建一个工具函数,在阻塞请求之前主动调用来预加载数据。`` 组件会根据 `checkIsAvailable()` 函数的返回值条件渲染。 + +你可以在 `checkIsAvailable()` 之前调用 `preload()` 来主动初始化 `` 的数据依赖。当 `` 渲染时,其数据已经获取完成。 -在开发过程中,您可以使用 [React Devtools](https://react.dev/learn/react-developer-tools) 预览和检查组件的加载状态。 \ No newline at end of file +```tsx filename="app/item/[id]/page.tsx" switcher +import { getItem } from '@/lib/data' + +export default async function Page({ + params, +}: { + params: Promise<{ id: string }> +}) { + const { id } = await params + // 开始加载项目数据 + preload(id) + // 执行另一个异步任务 + const isAvailable = await checkIsAvailable() + + return isAvailable ? : null +} + +export const preload = (id: string) => { + // void 会执行给定表达式并返回 undefined + // https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/void + void getItem(id) +} +export async function Item({ id }: { id: string }) { + const result = await getItem(id) + // ... +} +``` + +```jsx filename="app/item/[id]/page.js" switcher +import { getItem } from '@/lib/data' + +export default async function Page({ params }) { + const { id } = await params + // 开始加载项目数据 + preload(id) + // 执行另一个异步任务 + const isAvailable = await checkIsAvailable() + + return isAvailable ? : null +} + +export const preload = (id) => { + // void 会执行给定表达式并返回 undefined + // https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/void + void getItem(id) +} +export async function Item({ id }) { + const result = await getItem(id) + // ... +``` + +此外,你还可以使用 React 的 [`cache` 函数](https://react.dev/reference/react/cache) 和 [`server-only` 包](https://www.npmjs.com/package/server-only) 来创建一个可复用的工具函数。这种方法可以缓存数据获取函数,并确保它只在服务器端执行。 + +```ts filename="utils/get-item.ts" switcher +import { cache } from 'react' +import 'server-only' +import { getItem } from '@/lib/data' + +export const preload = (id: string) => { + void getItem(id) +} + +export const getItem = cache(async (id: string) => { + // ... +}) +``` + +```js filename="utils/get-item.js" switcher +import { cache } from 'react' +import 'server-only' +import { getItem } from '@/lib/data' + +export const preload = (id) => { + void getItem(id) +} + +export const getItem = cache(async (id) => { + // ... +}) +``` diff --git a/apps/docs/content/zh-hans/docs/01-app/01-getting-started/11-error-handling.mdx b/apps/docs/content/zh-hans/docs/01-app/01-getting-started/11-error-handling.mdx index 68d2a187..11146637 100644 --- a/apps/docs/content/zh-hans/docs/01-app/01-getting-started/11-error-handling.mdx +++ b/apps/docs/content/zh-hans/docs/01-app/01-getting-started/11-error-handling.mdx @@ -1,9 +1,9 @@ --- -source-updated-at: '2025-05-19T22:31:51.000Z' -translation-updated-at: '2025-05-19T22:31:51.000Z' +source-updated-at: 2025-05-21T18:33:43.000Z +translation-updated-at: 2025-05-21T19:17:12.404Z title: 错误处理指南 nav_title: 错误处理 -description: 学习如何显示预期错误并处理未捕获异常。 +description: 学习如何显示预期错误并处理未捕获的异常。 related: title: API 参考 description: 通过阅读 API 参考文档深入了解本页提到的功能。 @@ -14,17 +14,17 @@ related: - app/api-reference/file-conventions/not-found --- -错误可分为两类:[预期错误](#handling-expected-errors) 和 [未捕获异常](#handling-uncaught-exceptions)。本文将指导您如何在 Next.js 应用中处理这些错误。 +错误可分为两类:[预期错误](#handling-expected-errors) 和 [未捕获异常](#handling-uncaught-exceptions)。本指南将介绍如何在 Next.js 应用中处理这些错误。 ## 处理预期错误 -预期错误指应用正常运行过程中可能出现的错误,例如[服务端表单验证](/docs/app/building-your-application/data-fetching/server-actions-and-mutations#server-side-form-validation)失败或请求失败。这类错误应显式处理并返回给客户端。 +预期错误指应用正常运行过程中可能出现的错误,例如来自 [服务端表单验证 (server-side form validation)](/docs/app/building-your-application/data-fetching/server-actions-and-mutations#server-side-form-validation) 的验证错误或失败的请求。这类错误应被显式处理并返回给客户端。 ### 服务端函数 -您可以使用 [`useActionState`](https://react.dev/reference/react/useActionState) 钩子来处理[服务端函数 (Server Functions)](https://react.dev/reference/rsc/server-functions)中的预期错误。 +您可以使用 [`useActionState`](https://react.dev/reference/react/useActionState) 钩子来处理 [服务端函数 (Server Functions)](https://react.dev/reference/rsc/server-functions) 中的预期错误。 -对于这类错误,应避免使用 `try`/`catch` 代码块抛出错误,而应将预期错误建模为返回值。 +对于这类错误,应避免使用 `try`/`catch` 代码块和抛出错误,而应将预期错误建模为返回值。 ```ts filename="app/actions.ts" switcher 'use server' @@ -81,12 +81,12 @@ export function Form() { return (
- + - +