NextJS全栈入门

412 阅读6分钟

NextJS全栈入门

NextJS官网:www.nextjs.cn/

中文网: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...
 }