在使用最新版本的 Next.js 创建项目时,系统会提示我们选择使用 app/
目录还是 pages/
目录,并且推荐使用 app/
目录作为创建应用的优选方式。
通过本文的学习,我们将充分了解并掌握 app
目录强大而丰富的功能,利用其最大限度地发挥 Next.js 在 Web 开发方面的潜力。
相较于 pages/
目录,Next.js 的 app/
目录提供了更高的灵活性和更丰富的功能。接下来,我们将逐一探讨这些功能:
布局(Layout)
在 app/
目录下,利用 布局(Layout)
可以更高效地构建复杂界面,它支持嵌套布局,从而有效避免不必要的重复渲染,并在不同的页面之间保持用户界面的一致性。
我们可以通过在 app/
目录的根目录下创建一个 layout.jsx
文件来定义一个全局布局组件。此布局组件能够在所有页面中复用,实现一致的用户界面。
向布局组件添加元数据
元数据用于向页面提供额外信息,这些信息不会直接显示在网页的内容区域,但可以被浏览器、搜索引擎或网络爬虫读取和使用。
在 app/
目录中,我们可以通过 layout.js
文件向页面添加元数据(这些元数据将被所有页面所共享)。以下是一个示例代码片段,展示了如何从文件中导出元数据:
arduino
export const metadata = {
title: 'Keyword Title',
description: 'Any Keyword,Another Keyword, More Keywords ',
};
如果需要为不同页面设置特定的元数据,我们可以在目标页面文件中导出一个名为 metadata
的变量,用于覆盖 layout.js
文件中的元数据。
没有 _app.js
文件
如你所见,原先位于 pages/
目录下的 _app.jsx
文件在 app/
目录下已经消失,所有基础布局逻辑统一整合至 layout.jsx
文件中。
例如,为了使用 Chakra UI 实现全局样式和组件配置的统一管理,推荐将 Chakra UI 的 Provider 组件放置在 layout.jsx
文件中。下面是 Chakra UI 官方文档中的代码示例,演示了如何在 layout.jsx
文件中引入并配置 Chakra Provider:
javascript
// app/providers.tsx
'use client'
import { ChakraProvider } from '@chakra-ui/react'
export function Providers({ children }: { children: React.ReactNode }) {
return <ChakraProvider>{children}</ChakraProvider>
}
javascript
// app/layout.tsx
import { Providers } from './providers'
export default function RootLayout({
children,
}: {
children: React.ReactNode,
}) {
return (
<html lang='en'>
<body>
<Providers>{children}</Providers>
</body>
</html>
)
}
路由(Routing)
与 pages/
目录结构不同,app/
被设计为严格基于文件夹结构来定义,前者既支持基于文件夹的路由(通过文件夹组织页面),也支持基于文件的路由(路由路径直接映射到文件名)。
在 app/
目录中创建路由需要首先创建一个文件夹,该文件夹的名称将直接映射为路由路径的一部分。然后在该文件夹内创建一个 page.js
文件,该文件负责实现路由具体逻辑。
例如,如果我们创建一个名为 about
的文件夹,并在该文件夹中创建一个 page.js
文件,运行开发服务器,访问 localhost:3000/about
将会加载该 page.js
文件中定义的内容。
在 app/
目录中的任何位置创建的任何文件夹都将遵循此模式。
嵌套路由(Nested routing )
在 app/
目录下,通过在其他文件夹中创建文件夹的方式构建嵌套路由。每个文件夹对应一个路由,其中包含的 page.js
文件用于实现该文件夹的路由逻辑。
例如,对于 /dashboard/analytics
这样的 URL ,其对应的文件夹结构为 app/dashboard/analytics
,在 analytics
文件夹中,应该存在一个 page.js
文件,该文件负责 /dashboard/analytics
路由的显示逻辑和组件渲染,从而使得该路由可以通过 URL 公开访问。
路由组(Route group )
在 app/
目录中,文件夹通常映射到 URL 路径中。但是,我们可以将文件夹标记为路由组(Route group),以防止该文件夹包含在 URL 路径中。
这样,我们就可以在不影响 URL 路径的前提下,更好的组织和管理项目文件。
我们可以通过将文件夹名称括在括号中来创建路由组,例如 (name_of_folder)
,这样可以有效地将路由分组到该文件夹下,同时文件夹名称不会出现在路由中。
字体用法
在 Next.js 12 中,要在 pages/
目录下使用字体,需将字体样式表的链接复制到项目的 CSS 文件中。
但在 Next.js 13 中,我们可以在 app/
目录下通过使用 import
关键字从 next/font/google
导入所需的字体。
javascript
//importing the fonts
import { Inter } from 'next/font/google';
//initialising a variable
const inter = Inter({ subsets: ['latin'] });
export default function RootLayout({ children }) {
return (
<>
<html lang="en">
//Adding the variable as a class to the body tag
<body className={inter.className}>
{children}
</body>
</html>
</>
);
}
网站图标
为 Next.js 项目设置网站图标,需要使用选择图片替换位于项目根目录中的 favicon.ico
文件。请注意,如果图片格式为 JPG、 PNG或 SVG 等其他格式,需要先将其转换为 ICO 格式。
loading.jsx
文件
在 Next.js 中,利用加载组件(loading component)来展示数据加载状态是一种用户友好的做法。这种方式特别适用于需要从 API 获取数据并在数据加载过程中向用户展示加载状态的场景。
我们只需在 app/
目录下指定文件夹中创建名为 loading.jsx
的文件即可自定义加载组件。
下面是 loading.jsx
文件的一个实现示例:
javascript
// app/loading.jsx
const loadingPage = ()=>{
return (
<div className="loader">
<div id="loader-wrapper">
<div id="loader">
<img src="/img/Spinner-1s-120px.gif"/>
</div>
<div className="loader-section section-left">
</div>
<div className="loader-section section-right"></div>
</div>
</div>
)
}
export default loadingPage
error.jsx
文件
error.jsx
文件是 Next.js 13.4 版本新增的错误处理专用文件,此文件旨在替换传统的 pages/error.js
或 pages/_error.js
文件,以便以更集中的方式处理错误。
此文件一个显著优点是能够统一处理客户端和服务器端的错误。它通过接收 statusCode
属性来确定发生的错误类型,并据此显示相应的错误信息和应用特定的样式,从而提供更加用户友好的错误处理体验。
下面是一个 error.jsx
文件的示例,展示了其可能的代码结构:
javascript
// app/error.jsx
function Error({ statusCode }) {
return (
<div>
<h1>Error</h1>
<p>An error {statusCode} occurred on server</p>
</div>
);
}
Error.getInitialProps = ({ res, err }) => {
const statusCode = res ? res.statusCode : err ? err.statusCode : 404;
return { statusCode };
};
export default Error;
在上面的示例中,Error
组件通过 getInitialProps
方法接受 statusCode
属性。此方法首先检查响应对象 (res
) 和错误对象 (err
) 是否存在。如果 res
存在,则从 res
中获取状态码;如果 err
存在,则尝试从 err
中获取状态码。如果两者都不存在,则默认状态码为 404。然后,这个状态码被用于在错误页面中显示相应的错误消息,为用户提供清晰的反馈。
not-found.jsx
文件
在 Next.js 中,not-found.jsx
是一种特殊页面组件,专门用于处理用户尝试访问应用程序中不存在的路由时的情况。当请求的路由不存在时,该文件被用来渲染一个自定义的"404未找到"页面。
下面是一个 not-found.jsx
文件的示例,展示了其可能的代码结构:
javascript
// app/not-found.jsx
import Link from 'next/link';
export default function NotFound() {
return (
<div>
<h2>Not Found</h2>
<p>The page you were looking for does not exist.</p>
<Link href="/">Go back home</Link>
</div>
);
}
服务器组件
在 Next.js 的 app/
目录中默认启用服务器组件。这使得我们的组件可以自动实现服务器端渲染,而无需额外配置。
使用服务器组件可以带来多方面的好处:
- 数据获取: 服务器组件可以直接在服务器上处理数据,如数据库查询、API 调用等,无需通过客户端发送请求。
- 安全: 服务器组件允许将敏感的业务逻辑保留在服务器端,避免暴露给客户端,从而减少安全风险。
- 缓存: 服务器组件可以在服务器端实现高效的数据缓存,对于重复请求可以快速响应,减少服务器负载。
- 减少捆包尺寸: 可以根据需要动态打包服务器组件,从而显著减少发送到客户端的代码量。
- 搜索引擎优化 : 服务器组件通过在服务器端执行渲染,能够为搜索引擎爬虫提供完整的内容,有利于提高页面的 SEO 排名。
- 社交网络可分享性: 当页面内容通过服务器组件预渲染时,社交网络分享可以展示更丰富的预览信息。
服务器端渲染(SSR)与服务器组件的主要区别在于应用场景:服务器端渲染应用于 pages/
目录,而服务器组件应用于 app/
目录。
服务器组件巧妙地提供了一种利用服务器端逻辑的方式,从而避免了传统服务器端渲染(SSR)的负担,显著提升了现在 Web 应用程序的性能和可维护性。
尽管服务器端渲染(SSR)与服务器组件均在服务器端执行渲染,但服务器组件不支持与 JavaScript 的交互。因此,服务器组件无法进行事件处理以及使用 React 的状态管理功能(例如 useState、useEffect 和其他 DOM 操作)。
通过将 useClient
指令添加在代码的顶部,可以将默认的服务器组件转换为客户端组件,从而获得对这些功能的使用能力。
结语
Next.js 通过推出新的 app/
目录结构提供了一系列强大的功能,帮助开发人员提升了开发体验。
通过本文的学习,我相信你将有足够的信心,在 Next.js 开发中利用 app/
目录构建出功能强大、可扩展且可维护的应用程序。