NextJS全栈入门
NextJS官网:www.nextjs.cn/
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
在 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 dev或yarn 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"
}
一些细节:
你不应该从 getStaticProps 或 getStaticPaths 获取 API 路由。相反,请直接在 getStaticProps 或 getStaticPaths 中编写服务器端代码因为getStaticProps 和 getStaticPaths 仅在服务器端运行。它永远不会在客户端上运行。它甚至不会包含在浏览器的 JS 包中。这意味着可以编写代码,例如直接数据库查询,而无需将它们发送到浏览器。
API 路由的一个很好的用例是处理表单输入。例如,您可以在页面上创建一个表单,并让它向您的 API 路由发送 POST 请求。然后,您可以编写代码以将其直接保存到数据库中。API Route 代码不会成为您的客户端捆绑包的一部分,因此您可以安全地编写服务器端代码。
export default (req, res) => {
const email = req.body.email
// Then save email to your database, etc...
}