跳到主要内容

NextJS全栈入门

NextJS官网:https://www.nextjs.cn/

中文网:https://www.nextjs.cn/docs

Next.js 是一个基于 React 的框架,提供了一些在 React 中构建现代 Web 应用时常用的特性:

  • 服务器端渲染 (SSR): Next.js 支持服务器端渲染,可以在服务器端生成页面的 HTML,从而改善 SEO 和提高首屏加载速度。对于需要快速索引的内容,SSR 是一种重要的优化手段。

  • 静态站点生成 (SSG): Next.js 支持静态站点生成,可以在构建时预先生成所有页面的 HTML 文件,使得应用更快速,并且可以通过 CDN 进行分发。对于内容不频繁更新的网站,SSG 提供了极致的性能。

开始使用

创建nextjs应用:

npx create-next-app@latest

根据选项操作后启动应用:

npm run dev

导航

src/pages目录新建的文件会自动添加路由,例如新建一个src/pages/home.tsx

function HomePage() {
return <div>Welcome to Next.js!</div>
}

export default HomePage

image-20241129214503451

在 Next.js 中,页面是从pages 目录中的文件导出的 React 组件,页面根据其文件名与路由关联,使用<Link> 可以对其他页面进行客户端导航。

import Link from "next/link"

function HomePage() {
return <div>
Welcome to Next.js!

<Link href={"https://www.nextjs.cn"}> next js </Link>
</div>
}

export default HomePage

这个功能是客户端导航,也就是跳转了浏览器没有加载整个页面,客户端导航意味着页面转换使用 JavaScript 进行,这比浏览器完成的默认导航更快。

静态资源

Next.js 可以在顶级 public 目录下提供静态文件,如图像。public 中的文件可以从应用程序的根目录引用,例如我有一个文件public/vercel.svg,那么我可以使用:

<Image src="/next.svg" alt="Next.js Logo" width={48} height={48} />

想修改页面的元数据,比如 <title> HTML 标签,可以使用Head<Head> 是内置于 Next.js 中的 React 组件

    <Head>
<title>
First Blog
</title>
</Head>

此时打开浏览器预览,会发现Tab标签页显示的Title是First Blog

样式布局:

定义基础布局在src/components/layout.tsx

export default function Layout({ children }) {
return (
<div className="container flex">
{children}
</div>
);
}

使用布局src/pages/index.tsx

export default function Index() {
return <>

<Layout>
<Head>
<title>
博客主页
</title>
</Head>

<h1>博客首页</h1>
<h2>
<Link href={"/home"}>回家</Link>
<br/>
<Link href={"/blog"}>博客内容</Link>
</h2>
</Layout>
</>
}

要加载全局 CSS 文件,请在 pages创建一个名为 _app.js 的文件,并添加以下内容

import './global.css'
export default function App({ Component, pageProps }) {
return <Component {...pageProps} />
}

App 组件是顶级组件,在所有不同的页面中都是通用的。例如,您可以使用此 App 组件在页面之间导航时保持状态。

预渲染

默认情况下,Next.js 会预渲染每个页面。这意味着 Next.js 会提前为每个页面生成 HTML,而不是全部由客户端 JavaScript 完成。预渲染可以带来更好的性能和 SEO

生成的每个 HTML 都与该页面所需的最少 JavaScript 代码相关联。当浏览器加载页面时,其 JavaScript 代码将运行并使页面完全交互。(这个过程称为水化)

如果是普通React.js应用程序(没有 Next.js),则没有预渲染,因此如果禁用 JavaScript,将无法看到。

Next.js 有两种形式的预渲染:静态生成和服务器端渲染。区别在于它何时为页面生成 HTML。

  • 静态生成:是在构建时生成 HTML 的预渲染方法。然后,在每个请求中重复使用预渲染的 HTML。
  • 服务端渲染:是在每个请求上生成 HTML 的预渲染方法。

Next.js允许您选择要用于每个页面的预渲染表单。您可以通过对大多数页面使用静态生成,对其他页面使用服务器端渲染来创建“混合”Next.js应用程序。

静态生成

静态生成可以在有数据的情况下进行,也可以在没有数据的情况下完成。使用 getStaticProps 生成静态数据

在 Next.js 中,导出页面组件时,可以导出一个名为 getStaticProps异步函数,在该函数中,可以获取外部数据并将其作为 props 发送到页面。

export default function Home(props) { ... }

export async function getStaticProps() {
// Get external data from the file system, API, DB, etc.
const data = ...

// The value of the `props` key will be
// passed to the `Home` component
return {
props: ...
}
}

本质上,getStaticProps 允许你告诉Next.js:这个页面有一些数据依赖关系——当构建时预渲染这个页面时,一定要先解决它们,例如:


import { getSortedPostsData } from '../lib/posts'

export default function Home({ allPostsData }) {
return (
<Layout>
<Head></Head>
<section ></section>
<section >
<h2 >Blog</h2>
<ul >
{allPostsData.map(({ id, date, title }) => (
<li key={id}>
{title}
<br />
{id}
<br />
{date}
</li>
))}
</ul>
</section>
</Layout>
)
}
export async function getStaticProps() {
const allPostsData = getSortedPostsData()
return {
props: {
allPostsData
}
}
}

lib/posts.js 中,实现了 getSortedPostsData,它从文件系统中获取数据。

  • 开发中(npm run devyarn dev),getStaticProps 在每个请求上运行。

  • 生产环境中,getStaticProps构建时运行。

服务端渲染

如果需要在请求时而不是在构建时获取数据,可以尝试服务器端渲染:

要使用服务器端渲染,你需要从页面导出 getServerSideProps而不是 getStaticProps

export async function getServerSideProps(context) {
return {
props: {
// props for your component
}
}
}

因为 getServerSideProps 是在请求时调用的,所以它的参数 (context) 包含特定于请求的参数。

客户端渲染策略:

  • 静态生成(预呈现)不需要外部数据的页面部分
  • 当页面加载时,使用 JavaScript 从客户端获取外部数据并填充其余部分。

动态路由

使用动态路由静态生成页面

我们想为博客文章创建动态路由,每个帖子都有路径 /posts/<id>,其中 <id> 是顶级 posts 目录下的 markdown 文件的名称。

pages/posts 下创建一个名为 [id].js 的页面。以 [ 开头并以 ] 结尾的页面是 Next.js 中的动态路由

import Layout from "@/components/layout";

export default function Post() {
return <Layout>...</Layout>
}

export async function getStaticPaths() {
// Return a list of possible value for id
}

从此页面导出一个名为 getStaticPaths 的异步函数。在这个函数中,我们需要返回 id可能值列表。

再次实现 getStaticProps 为具有给定 id 的博客文章获取必要的数据。 getStaticProps 被赋予 params,其中包含 id (因为文件名是 [id].js)。

import Layout from "@/components/layout";
import { getAllPostIds, getPostData } from "@/lib/posts";
export default function Post({ postData }) {
return (
<Layout>
{postData.title}
<br />
{postData.id}
<br />
{postData.date}
</Layout>
)
}

export async function getStaticPaths() {
const paths = getAllPostIds()
return {
paths,
fallback: false
}
}
export async function getStaticProps({ params }) {
const postData = getPostData(params.id)
return {
props: {
postData
}
}
}

此时即可实现动态路由的效果

API路由

Next.js 支持 API 路由,可让您轻松创建 API 终端节点作为Node.js无服务器函数。API 路由允许您在 Next.js 应用程序内创建 API 终端节点。您可以通过在 pages/api 目录中创建一个格式如下的函数来执行此操作:

// req = request data, res = response data
export default (req, res) => {
// ...
}

例如,在pages/api/hello.tsx中创建接口:

export default (req, res) => {
res.status(200).json({ text: 'Hello' })
}

此时访问:http://localhost:3000/api/hello

可以拿到结果:

{
"text": "Hello"
}

一些细节:

你不应该从 getStaticPropsgetStaticPaths 获取 API 路由。相反,请直接在 getStaticPropsgetStaticPaths 中编写服务器端代码因为getStaticPropsgetStaticPaths 仅在服务器端运行。它永远不会在客户端上运行。它甚至不会包含在浏览器的 JS 包中。这意味着可以编写代码,例如直接数据库查询,而无需将它们发送到浏览器。

API 路由的一个很好的用例是处理表单输入。例如,您可以在页面上创建一个表单,并让它向您的 API 路由发送 POST 请求。然后,您可以编写代码以将其直接保存到数据库中。API Route 代码不会成为您的客户端捆绑包的一部分,因此您可以安全地编写服务器端代码。

export default (req, res) => {
const email = req.body.email
// Then save email to your database, etc...
}