|
Next.js 是一个用于构建 Web 应用程序的框架。Next.js 是一个用于生产环境的 React 框架,是一个 React 服务端渲染应用框架。
Next.js 具有同类框架中最佳的 “开发人员体验” 和许多内置功能,它的特点如下:
(1) 直观的、 基于页面 的路由系统(并支持 动态路由); (2) 预渲染,支持在页面级的 静态生成 (SSG) 和 服务器端渲染 (SSR) (3) 自动代码拆分,提升页面加载速度; (4) 具有经过优化的预取功能的 客户端路由; (5) 内置 CSS 和 Sass 的支持,并支持多数 CSS-in-JS 库; (6) 开发环境支持快速刷新; (7) 利用 Serverless Functions 及 API 路由 构建 API 功能; (8) 完全可扩展;
Next.js 被用于数以万计的的网站和 Web 应用程序,包括许多世界上许多最大的品牌都在使用 Next.js。
NextJS: https://nextjs.org/ NextJS GitHub: https://github.com/vercel/next.js React: https://www.reactjs.org/ (https://react.dev) React GitHub: https://github.com/facebook/react
1. 系统环境
操作系统:CentOS 7.9 (x64) NodeJS: 16.20.0 NPM: 8.19.4 NVM: 0.39.2 NextJS: 13.4.12
2. 创建 Next.js 项目
安装 create-next-app 脚手架,命令如下:
# 使用 -g 参数,表示该命令只需在本机上运行一次 $ npm install -g create-next-app
...
使用 create-next-app 命令创建 NextJS 项目,命令如下:
$ create-next-app nextjs-demo
√ Would you like to use TypeScript? ... No
√ Would you like to use ESLint? ... No
√ Would you like to use Tailwind CSS? ... No
√ Would you like to use `src/` directory? ... Yes
√ Would you like to use App Router? (recommended) ... No
√ Would you like to customize the default import alias? ... Yes
Creating a new Next.js app in /home/develop/nodejs/nextjs-demo.
Using npm.
Initializing project with template: default
Installing dependencies:
- react
- react-dom
- next
added 23 packages in 5s
Initialized a git repository.
Success! Created nextdemo at /home/develop/nodejs/nextjs-demo
注:在 Next.js 13 之前,Pages Router 是在 Next.jsp 中创建路由的主要方式。它使用直观的文件系统路由器将每个文件映射到一个路由。新版本的 Next.js 仍然支持 Pages Router,Next.js 官方建议迁移到新的 App Router,以利用 React 的最新功能。本文主要介绍基于 Pages Router 的 Web 应用,所以第 5 个选项选了 No,表示选择了 Pages Router。
也可以使用 npx 命令直接创建 NextJS 项目,命令格式如下:
$ npx create-next-app nextjs-demo
注:npx 是 npm 5.2.0 及更高版本中包含的一个命令行工具,用于执行本地安装的或在线安装的 Node.js 包中的命令。npm 主要用于管理和安装依赖包,而 npx 主要用于运行本地或在线安装的包中的命令。
3. 运行 Next.js 项目
1) 项目目录结构
整个项目的目录结构:
├── public
│ ├── favicon.ico # Favicon
│ ├── next.svg
│ └── vercel.svg
├── src
│ ├── pages # Page Router
│ │ ├── api
│ │ │ └── hello.js
│ │ ├── _app.js
│ │ ├── _document.js
│ │ └── index.js # home Page
│ │
│ └── styles
│ ├── globals.css
│ └── Home.module.css
│
├── jsconfig.json # JavaScript 配置文件
├── next.config.js # Next.js 配置文件
├── package-lock.json # 项目依赖和脚本(锁定),运行 npm install 后自动生成
├── package.json # 项目依赖和脚本
└── README.md
2) 启动项目
进入 nextjs-demo 目录安装依赖,命令如下:
$ npm install
...
开发模式运行,命令如下:
$ npm run dev
> nextjs-demo@0.1.0 dev
> next dev
- ready started server on 0.0.0.0:3000, url: http://localhost:3000
...
生产模式运行,命令如下:
$ npm run build
> nextjs-demo@0.1.0 build
> next build
...
$ npm run start
> nextjs-demo@0.1.0 start
> next start
- ready started server on 0.0.0.0:3000, url: http://localhost:3000
...
使用浏览器访问 http://ip:3000,本机上可以访问 http://localhost:3000。
4. 路由 (Routing)
页面路由器 (Page Router) 有一个基于页面概念的文件系统路由器。当一个文件被添加到 src/pages (或 pages) 目录时,它会自动作为路由使用。
在 Next.js 中,页面是从 src/pages (或 pages) 目录中的 .js、.jsx、.ts 或 .tsx 文件导出的 React 组件,并且每个页面都根据其文件名与一个路由相关联。
1) 文件名路由
在 src/pages 目录下创建 test.js 文件,内容如下:
export default (props) => {
return (
<div>Test Page</div>
)
}
使用浏览器访问 http://localhost:3000/test,显示内容如下:
Test Page
显然 /test 被路由到 src/pages/test.js 文件,这里的路径是大小写敏感的,即 /TEST 和 /test 不是同一路径。
2) 索引路由
路由将自动将名为 index 的文件映射到 index 所在目录,具体规则如下: src/pages/index.js -> / src/pages/hello/index.js /hello
在 src/pages 目录下创建 hello 子目录,并在 hello 目录下创建 index.js 文件,内容如下:
export default (props) => {
return (
<div>Hello - Index Page</div>
)
}
使用浏览器访问 http://localhost:3000/hello,显示内容如下:
Hello - Index Page
3) 嵌套路由 (多级目录+文件名)
路由支持嵌套文件,具体规则如下:
src/pages/hello/world.js -> /hello/world src/pages/hello/nested/router.js -> /hello/nested/router
在 src/pages 目录下创建 hello/nested 两级子目录,并在 nested 目录下创建 router.js 文件,内容如下:
export default (props) => {
return (
<div>Hello/nested - router Page</div>
)
}
使用浏览器访问 http://localhost:3000/hello/nested/router,显示内容如下:
Hello/nested - router Page
4) 动态路由
Next.js 支持具有动态路由的页面,具体规则如下: src/pages/hello/[id].js -> /hello/*
在 src/pages/hello 目录下创建 "[id].js" 文件,内容如下:
import { useRouter } from 'next/router'
export default () => {
const router = useRouter()
return <p>Hello: {router.query.id}</p>
}
使用浏览器访问 http://localhost:3000/hello/5,显示内容如下:
Hello: 5
5) API 路由
使用 App Router 的项目,可以直接使用服务器组件或路由处理程序,不需要使用 API 路由。这里的 API 路由,是指在使用了 Page Router 的项目里,在文件夹 src/pages/api 目录中的任何文件,都会被自动映射到 /api/*,并将被视为 API 端点而不是页面。 上文的 nextjs-demo 项目里,create-next-app 命令自动创建了文件 src/pages/api/hello.js,它就是一个 API 端点,内容如下:
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
export default function handler(req, res) {
res.status(200).json({ name: 'John Doe' })
}
使用浏览器访问 http://localhost:3000/api/hello,显示内容如下:
{"name":"John Doe"}
API 路由在 next.config.js 中的相关配置属性是 pageExtensions。
5. 页面布局 (Layout)
React 模型允许我们将页面解构为一系列组件,其中许多组件经常在页面之间重复使用,比如在每一页上都有相同的导航栏和页脚等。
1) App 组件
Next.js 使用 App 组件来初始化页面。App 组件除了控制页面初始化之外,还能完成如下功能:
(1) 在页面更改之间创建共享布局 (2) 将附加数据注入页面 (3) 添加全局 CSS
(1) 自定义 App 组件 可以在 src/pages 目录下添加 _app.js 文件,内容如下:
export default ({ Component, pageProps }) => {
return <Component {...pageProps} />
}
其中 Component 是动态页面(或当前页面),导航切换页面时,Component 都会更改为导航后的新页面。pageProps 是一个带有初始属性的对象,这些属性是通过某种数据获取方法为页面预加载的,否则它就是一个空对象。
注:
(1) 如果 App 组件正在运行,并且添加了自定义 App 组件(即新增了 src/pages/_app.js 文件),则需要重新启动 NextJS 服务。 (2) App 组件 不支持的 Next.js 数据获取方法,如 getStaticProps 或 getServerSideProps。
(2) getInitialProps 属性
在 App 组件中可以使用 getInitialProps 将对没有 getStaticProps 的页面禁用自动静态优化。
import App from 'next/app'
export default function MyApp({ Component, pageProps, example }) {
return (
<>
<p>Data: {example}</p>
<Component {...pageProps} />
</>
)
}
MyApp.getInitialProps = async (context) => {
const ctx = await App.getInitialProps(context)
return { ...ctx, example: 'data' }
}
不建议使用此模式。相反,可以考虑逐步采用 App 路由器,这样可以更容易地获取页面和布局的数据。
2) Document 组件
Document 组件可以更新用于渲染 (render) 页面的 <html> 和 <body> 标记。
(1) 自定义 Document 组件 可以在 src/pages 目录下添加 _document.js 文件,内容如下:
import { Html, Head, Main, NextScript } from 'next/document'
export default function Document() {
return (
<Html lang="en">
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
注: (1) Document 组件仅在服务器上渲染 (render),因此 onClick 这类的事件处理程序不能在此文件中使用。 (2) 要正确渲染页面,需要 <Html>、<Head/>、<Main/> 和 <NextScript/>。 (3) _document.js 中使用的 <Head/> 组件与 next/head 不同。此处使用的 <Head/> 组件应仅用于所有页面通用的任何 <Head> 代码。对于所有其他情况,如<title>标记,建议在页面或组件中使用 next/head 。 (4) <Main/> 之外的 React 组件不会被浏览器初始化。不要在此处添加应用程序逻辑或自定义 CSS(如样式 jsx)。 (5) Document 组件不支持的 Next.js 数据获取方法,如 getStaticProps 或 getServerSideProps。
(2) 自定义 renderPage
自定义 renderPage 是高级选项,只有在需要 CSS-in-JS 等库来支持服务器端渲染时才需要,对于内置样式的 jsx 支持来说是不需要的。
import Document, { Html, Head, Main, NextScript } from 'next/document'
class MyDocument extends Document {
static async getInitialProps(ctx) {
const originalRenderPage = ctx.renderPage
// Run the React rendering logic synchronously
ctx.renderPage = () =>
originalRenderPage({
// Useful for wrapping the whole react tree
enhanceApp: (App) => App,
// Useful for wrapping in a per-page basis
enhanceComponent: (Component) => Component,
})
// Run the parent `getInitialProps`, it now includes the custom `renderPage`
const initialProps = await Document.getInitialProps(ctx)
return initialProps
}
render() {
return (
<Html lang="en">
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument
不建议使用此模式。相反,可以考虑逐步采用 App Router,这样可以更容易地获取页面和布局的数据。
注:
(1) 在客户端转换期间,不会调用 _document 中的 getInitialProps。 (2) _document 的 ctx 对象等效于在 getInitialProps 中接收到的对象,添加了 renderPage。
3) 自定义页面布局
在上文 nextjs-demo 项目基础上,创建 src/components 目录,这里 components 和 pages 目录在同一级目录中。
创建 src/components/layout.js 文件,内容如下:
import Navbar from './navbar'
import Footer from './footer'
export default function Layout({ children }) {
return (
<>
<Navbar />
<main>{children}</main>
<Footer />
</>
)
}
创建 src/components/navbar.js 文件,内容如下:
export default () => {
return (
<>
<div>Navbar</div>
</>
)
}
创建 src/components/footer.js 文件,内容如下:
export default () => {
return (
<>
<div>Footer</div>
</>
)
}
修改 src/pages/_app.js 文件,内容如下:
import Layout from '../components/layout'
export default ({ Component, pageProps }) => {
return (
<Layout>
<Component {...pageProps} />
</Layout>
)
}
使用浏览器访问 http://localhost:3000/test,显示内容如下:
Navbar Test Page Footer
4) Errors 页面
(1) 404 页面
404 页面可能经常被访问。服务器为每次访问呈现一个错误页面会增加 Next.js 服务器的负载,这可能导致成本增加和体验缓慢。
为了避免上述陷阱,Next.js 默认情况下提供了一个静态 404 页面,而无需添加任何额外的文件。
自定义 404 页面,可以在 src/pages 添加 404.js 文件,内容如下:
export default function Custom404() { return <h1>404 - Page Not Found</h1> }
注:如果需要在构建时获取数据,可以在此页面中使用 getStaticProps。
(2) 500 页面
服务器为每次访问呈现错误页面会增加响应错误的复杂性。为了帮助用户尽快获得对错误的响应,Next.js 默认情况下提供了一个静态 500 页面,而无需添加任何其他文件。 自定义 500 页面,可以在 src/pages 目录下添加 500.js 文件,内容如下: export default function Custom500() { return <h1>500 - Server-side error occurred</h1> } 注:如果需要在构建时获取数据,可以在此页面中使用 getStaticProps。
(3) Error 组件
Error 组件同时处理客户端和服务器端的 500 错误。 自定义 Error 组件,可以在 src/pages 目录下添加 _error.js 文件,内容如下:
function Error({ statusCode }) {
return (
<p>
{statusCode
? `An error ${statusCode} occurred on server`
: 'An error occurred on client'}
</p>
)
}
Error.getInitialProps = ({ res, err }) => {
const statusCode = res ? res.statusCode : err ? err.statusCode : 404
return { statusCode }
}
export default Error
_error.js 仅在生产环境中使用。在开发过程中,一般调用堆栈中得到一个错误,以了解错误的来源。
(4) 重用内置错误页
要渲染内置错误页面,可以通过导入 Error 组件,格式如下:
import Error from 'next/error'
export async function getServerSideProps() {
const res = await fetch('https://api.github.com/repos/vercel/next.js')
const errorCode = res.ok ? false : res.status
const json = await res.json()
return {
props: { errorCode, stars: json.stargazers_count },
}
}
export default function Page({ errorCode, stars }) {
if (errorCode) {
return <Error statusCode={errorCode} />
}
return <div>Next stars: {stars}</div>
}
注:
Error 组件不支持 Next.js 数据获取方法,如 getStaticProps 或 getServerSideProps。 _error 和 _app 一样,是一个保留的路径名,_error 用于定义错误页面的自定义布局和行为。当访问路径是 /_error 时,会自动跳转到 404 页面。
6. 使用 Ant Design
Ant-Design 是采用 React 封装了一套 Ant Design 的组件库。Ant Design 的模块化设计方式,用户可以快速建立一个新的应用程序,它还提供丰富的 UI 组件和高可定制,用户可以完全按照自己的需求来进行个性化设置。
Ant Design 支持跨端统一设计,并可以满足开发者因技术栈而异的不同设计习惯,能够帮助他们实现跨端开发的融合,加快项目实施的进度。Ant Design 还提供了丰富的文档,从概念引导到实践指南,用户可以利用文档获取设计新灵感,同时也提升了自己对软件设计,交互和用户体验的认知水平。
Ant Desing: https://ant.design/index-cn
1) 安装 Ant Design
进入 NextJS 项目目录,运行如下命令:
$ npm install antd
命令运行成功后,查看 package.json 文件,在 "dependencies" 部分多了如下内容:
{
...
"dependencies": {
"antd": "^4.5.2",
...
}
}
以上命令安装了 latest 版的 antd,可以指定安装版本,本文使用 npm install antd@4.5.2 命令安装 Ant Design 4.5.2 。 也可以先修改 package.json 文件,指定 antd 的版本,比如 "antd": "^4.5.2",再运行 npm install 命令。
2) 使用 antd 组件
在上文 nextjs-demo 项目基础上,修改 src/pages/_app.js 文件,内容如下:
import 'antd/dist/antd.min.css';
import Layout from '../components/layout'
export default ({ Component, pageProps }) => {
return (
<Layout>
<Component {...pageProps} />
</Layout>
)
}
注:添加了 antd/dist/antd.min.css
修改 src/components/navbar.js 文件,内容如下:
import React, { useState } from 'react';
import { HomeOutlined, LoginOutlined, SettingOutlined } from '@ant-design/icons';
import { Menu } from 'antd';
const items = [
{
label: 'Home',
key: 'home',
icon: <HomeOutlined />,
},
{
label: 'Login',
key: 'login',
icon: <LoginOutlined />,
},
];
const Navbar = () => {
const [current, setCurrent] = useState('home');
const onClick = (e) => {
//console.log('click ', e);
setCurrent(e.key);
};
return <Menu onClick={onClick} selectedKeys={[current]} mode="horizontal" items={items} />;
};
export default Navbar;
以上代码使用了 antd 的 Menu 组件和 Icon 组件,使用浏览器访问 http://localhost:3000/test,显示内容如下:
Home Login # 菜单 Test Page Footer
来源:https://www.cnblogs.com/tkuang/p/17612546.html |