Next.js 乍一看好像令人生畏,由于有这么多新概念需求把握。但别担心——在这个循序渐进的教程中,我将为您供给运用 Next.js 创立您的第一个现代全栈应用程序所需的一切基本信息。

在本教程中,我将带您了解 Next.js 的基础常识,并辅导您创立您的第一个全栈应用程序。在本教程完毕时,您将有信心开端运用 Next.js 构建您自己的全栈应用程序。

因而,让咱们直接进入并一起开释 Next.js 的力气。

(NextJs教程:java567.com/search.html?sWord=next&v=2306015)

以下是咱们将介绍的内容:

  • 咱们要制作什么?
  • 入门
  • 如安在 Next.js 中创立同享布局
  • 如安在 Next.js 中创立自界说导航栏
  • 如安在 Next.js 中创立 API 路由
  • 怎么树立主页
  • Next.js 中的 App Router 是什么?
  • 怎么增强 Next.js 代码库的模块化和可维护性
  • 怎么创立动态人物页面
  • 如安在 Next.js 中创立动态 API 路由
  • 如安在 Next.js 中创立动态 UI 路由
  • Next.js 中有什么generateStaticParams
  • dynamicParamsNext.js 生成静态页面的意图是什么?
  • 怎么生成静态页面generateStaticParams
  • 怎么树立检验部分
  • 如安在 Next.js 中创立客户端组件
  • 定论

好吧,让咱们开端吧!

咱们要制作什么?

在本教程中,咱们将创立一个引人入胜的应用程序来展现有关恶搞之家人物的信息。此外,咱们将包括一个检验部分,用户能够在其间检验他们对节意图了解。

为了让您简略了解,咱们将防止运用数据库,而是运用本地 JSON 数据。经过消除数据库集成的复杂性,咱们能够专心于把握 Next.js 的基本概念。

如何使用Next.js创建全栈应用程序
申请预览

入门

要开端学习本教程,我强烈主张运用我专门为本教程创立的入门样板。它现已包括必要的依靠项和文件夹结构,然后节省了您名贵的时刻,无需从头开端设置您的项目。

只需从 GitHub 存储库中克隆入门样板,然后按照教程进行操作。这样,您就能够专心于学习和施行这些概念,而不会陷入设置细节中。

  • 入门样板:在 GitHub 上查看
  • 终究版别:在 GitHub 上查看

设置发动样板并在本地核算机上成功运转后,您应该能够看到初始页面。此页面标志着咱们教程的开端,并将作为咱们旅程的起点。

如何使用Next.js创建全栈应用程序
样板的初始页面

从这儿开端,咱们将逐渐构建现有代码并在咱们的应用程序中完成一些很帅的功用。让咱们开端吧,立刻开端吧!

如安在 Next.js 中创立同享布局

一般在您的应用程序中,您有跨多个页面同享的元素,例如导航栏或页脚。手动将这些元素增加到每个页面或许既庸俗又容易犯错。幸运的是,Next.js 供给了一种快捷的办法来创立可在整个应用程序中重复运用的同享布局。

第一种布局称为根布局。顾名思义,此布局在咱们应用程序的一切页面之间同享。它作为最顶层的布局,为咱们的整个应用程序供给了共同的结构。Root Layout 是必需的,咱们需求确保它包括必要的 HTML 和 body 标签。

接下来,让咱们考虑应用程序中的各个路由段。每个段都能够挑选界说自己的布局。这些布局类似于根布局,将在该段内的一切页面之间同享。这答应您为应用程序的不同部分设置特定的布局,一起仍然在每个部分中保持共同的结构。

现在,翻开app/layout.js并向其间增加以下代码:

//  app/layout.jsconst inter = Inter({ subsets: ['latin'] })
​
export const metadata = {
 title: 'Family Guy',
 description: 'Come here and learn more about Family Guy!',
}
​
export default function RootLayout({ children }) {
 return (
  <html lang="en">
   <body className={inter.className}>
    <Navigation />
     {children}
   </body>
  </html>
  )
}

您在这儿看到的组件是 Root Layout 组件,它在为整个应用程序创立同享布局方面起着至关重要的作用。让咱们仔细看看它的结构和功用。

在组件中,您界说metadata目标,其间包括应用程序的默认元数据标签。该title特点指定您的应用程序的标题,而该description特点供给简短的描绘。这些元数据标签关于查找引擎优化 (SEO) 很重要,假如需求能够针对特定路途掩盖这些标签。

RootLayout函数内部,您能够运用htmlbody符号构建 HTML 文档。您将符号lang的特点设置html"en"以指示内容是英文的。

body符号中,您包括Navigation从目录导入的组件components。该组件代表您的导航栏,并将在您的应用程序的一切页面之间同享。经过将其包括在此处,您能够确保它在整个应用程序中始终如一地显现。

propchildren是一个特别的 prop,代表组件内出现的内容RootLayout。这答应您在同享布局中嵌套其他组件和内容。

终究,您导出RootLayout组件,使其可用于整个应用程序。

如安在 Next.js 中创立自界说导航栏

在本节中,您将为您的应用程序创立一个简略的导航栏组件。导航栏将包括一个徽标和一个将用户带到检验部分的链接。翻开components/Navigation.jsx并增加以下代码:

//  components/Navigation.jsxexport const Navigation = () => {
 return (
  <div className="sticky top-0 backdrop-blur-xl bg-[rgba(0,0,0,0.8)] border-b border-slate-800 z-50">
   <Container className="flex justify-between py-5">
    <Link href="/">
     <Image src="/logo.png" alt="Family Guy" width={70} height={50} />
    </Link>
    <Link
     href="/quiz"
     className="flex items-center justify-center gap-1 px-5 font-semibold text-black transition-colors bg-green-500 rounded-md duration-600 hover:bg-green-600"
    >
     <TbArrowBigRightFilled className="text-lg" />
      Take a Quiz
    </Link>
   </Container>
  </div>
  )
}

现在你有了Navigation在整个应用程序中同享的粘性组件。假如你翻开你的本地服务器,你应该能够看到以下成果:

如何使用Next.js创建全栈应用程序
粘性导航栏预览

祝贺你到目前为止的进步!您现已为您的 Next.js 应用程序成功创立了一个带有导航栏的同享布局。这种同享布局可确保一切页面的共同性,然后更轻松地管理整个应用程序中的导航栏等元素。

现在,是时分专心于构建主页来显现字符了。为了在主页上显现这些字符,您需求创立一个 API 路由来从您的本地 JSON 文件中检索一切字符,然后答应您运用相关信息动态填充主页。

如安在 Next.js 中创立 API 路由

Next.js 中的路由是一个基本概念,它决议了怎么拜访应用程序的不同部分。当你在 Next.js 的目录中创立一个文件夹时app,它会主动成为一个路由。但是您能够灵敏地界说它应该是 UI 路由仍是 API 路由。

命名路由文件夹中的文件page.jsx会将其转换为 UI 路由。这意味着它将充任带有 UI 组件的常规页面。另一方面,假如你将文件命名为route.js,它就变成了一个 API 路由。这标明它将处理 API 恳求和呼应。

请务必记住,在单个目录中,您能够具有 UI 路由或 API 路由,但不能一起具有两者。这种清晰的别离答应在构建 Next.js 应用程序时有一个洁净和有安排的结构。

鄙人一节中,您将在 Next.js 中创立您的第一个 API 路由。Next.js 中的 API 路由供给了一种在应用程序中创立服务器端端点的简略方便的办法。

运用 API 路由,您能够界说处理 HTTP 恳求和呼应的自界说路由,答应您获取或修改数据、履行服务器端核算或与外部服务集成。

这些路由被编写为 JavaScript 函数,在云中主动布置为无服务器函数。API 路由在您的前端 Next.js 应用程序中供给类似后端的功用,使您能够构建动态和交互式 Web 应用程序,而无需独自的服务器。

怎么树立主页

在本节中,您将创立一个 API 路由,使您能够检索存储在本地 JSON 文件中的一切可用字符。经过施行此 API 路由,您将能够获取字符并将其显现在应用程序的主页上。

怎么创立字符 API 路由

为了确保 API 代码和 UI 代码之间的清晰别离,您将在目录中放置一切 API 路由app/api

经过选用这种办法,您能够有效地将与 API 相关的功用与用户界面阻隔开来,然后促进更好的安排和可维护性。

本节将辅导您完成创立 Characters API 路由的进程。只需翻开app/api/characters/route.js文件并增加以下代码:

//  app/api/characters/route.jsexport async function GET() {
 return NextResponse.json({ characters: characters.data })
}

在此代码片段中,您将导入一个名为 .json 的 JSON 文件characters.json。该文件包括有关您要在应用程序中运用的字符的数据。

NextResponse接下来,您将从模块中导入目标next/server。此目标供给用于处理 Next.js 应用程序中的服务器呼应的函数。

之后,您界说一个名为 的异步函数GET()。此函数与 HTTP GET 恳求办法相关联,该办法一般用于从服务器检索数据。

在函数内部GET(),您运用该NextResponse.json()函数来结构服务器呼应。您传递一个具有名为 的特点的目标characters,该目标保存文件中的数据characters.json。然后从函数回来此呼应。

简而言之,这段代码正在创立一个呼应 GET 恳求的 API 路由。当向该路由宣布 GET 恳求时,它会回来一个包括文件数据的 JSON 呼应characters.json。这答应您从您的应用程序中获取字符数据并将其用于咱们代码的其他部分。

现在,是时分检验您的 API 路由并确保一切正常运转了。为了简化此进程,您将运用浏览器本身来宣布 API 恳求。翻开浏览器并输入以下 URL:http://localhost:3000/api/characters。

履行此操作后,您将被定向到一个页面,您能够在其间观察 API 恳求的成果。这一步答应咱们验证 API 路由是否按预期作业并且它是否成功获取字符数据:

如何使用Next.js创建全栈应用程序
浏览器中的 JSON 数据

这是包括字符列表的 JSON 数据。假如 JSON 数据在您的浏览器中看起来很奇怪,请确保在您的浏览器上装置 JSON Formatter 扩展。我运用的是谷歌浏览器,所以我在我的浏览器上运用了这个 JSON Formatter。

如安在主页显现字符

现在您现已设置了 API,让咱们为咱们的主页创立 UI 并显现字符。为此,翻开app/page.jsx文件并增加以下代码片段:

//  app/page.jsxasync function getAllCharacters() {
 const data = await fetch(`${endpoint}/characters`)
​
 if (!data.ok) {
  throw new Error('Failed to fetch data')
  }
​
 return data.json()
}
​
export default async function Page() {
 const data = await getAllCharacters()
​
 return (
  <main>
   <Container className="grid grid-cols-2 gap-1 py-5 md:grid-cols-3 lg:grid-cols-4">
     {data?.characters?.map(item => {
     return (
      <Link
       href={`/characters/${item.slug}`}
       key={item.name}
       className="overflow-hidden rounded-md"
      >
       <Image
        src={item.avatar}
        alt=""
        className="transition-all duration-500 hover:scale-110 hover:-rotate-2"
        width={500}
        height={500}
       />
      </Link>
      )
     })}
   </Container>
  </main>
  )
}

在上面的代码片段中,您有一个名为 React 的组件Page,它被界说为一个异步函数。该组件担任烘托主页 UI。

首要,您调用了一个异步函数getAllCharacters,该函数运用“fetch”函数向 API 端点宣布异步 HTTP 恳求。此恳求的呼应存储在data变量中。

接下来,您将进行过错处理查看。假如 HTTP 呼应回来过错(状况代码不是 200),咱们将抛出一个过错,标明数据获取失败。

转到组件Page,它等待调用函数的成果getAllCharacters 。成果数据存储在data变量中。

return 语句出现主页的 UI。它运用一个main标签作为尖端容器和一个Container组件来保存具有多列的网格布局。

在 中Container,您映射目标characters中的数组data并生成项目列表。关于每个人物,咱们创立一个“链接”组件,用作指向特定人物页面的可点击链接。链接的 URL 是依据人物的 slug 特点生成的。

在 中Link,您有一个Image显现人物头像图画的组件。

总的来说,此代码从 API 端点获取数据,特别是字符数据。然后,它运用此数据动态出现人物化身的网格布局,并带有指向各个人物页面的可点击链接。

如何使用Next.js创建全栈应用程序
主页

您的主页现在看起来很棒,但您或许现已注意到咱们获取数据的办法有些不寻常。一般,您或许了解运用 useEffect 挂钩从 API 获取数据。但在这种情况下,您没有运用任何钩子——但您的代码运转良好。

鄙人一节中,咱们将仔细研讨这个组件中终究发生了什么。经过查看代码及其履行,您将对 Next.js 机制有更深化的了解。

Next.js 中的 App Router 是什么?

Next.js 中的 App Router 引入了一种利用 React 的最新功用开发应用程序的新典范。假如您现已了解 Next.js,您会发现 App Router 代表了依据文件系统的现有 Pages Router 的自然演化。

默认情况下,App Router 基本上使您能够在服务器上运转 React 代码,因而您在服务器上获取数据并且只将静态 HTML 回来给客户端。这意味着咱们有一个服务器组件,它从服务器检索数据并在服务器端出现其内容。

有一个需求考虑的警告:您将无法拜访服务器组件中的 React 状况和 React Hooks 等客户端功用,由于它们仅在服务器上运转。

假如要运用客户端功用,则必须经过"use client"在文件顶部增加来在组件文件中指定它。

Next.js 中服务器端烘托的含义安在?

在 Next.js 中,SSR 答应服务器生成网页的 HTML 内容并将其发送到浏览器。这意味着当您拜访 Next.js 网站时,您不用等待 JavaScript 代码在浏览器上加载和履行就能够看到任何内容。相反,服务器会发送一个预出现的 HTML 页面,该页面几乎能够当即显现。

SSR 的优势在于它能够缩短网页的初始加载时刻,供给更快、更无缝的用户体会。它还有助于查找引擎优化 (SEO),由于查找引擎能够轻松抓取和索引服务器出现的 HTML 内容。

Next.js 中的服务器端烘托办法

Next.js 供给了几种烘托页面的办法。这些办法中的每一个都有特定的用途,并且能够在不同的场景中运用:

  • 静态站点生成 (SSG): 静态生成是一种服务器端出现办法,其间 Next.js 在构建时生成 HTML。在构建进程中,Next.js 从 API 或其他数据源获取数据并预出现 HTML 页面。然后能够依据恳求将这些预出现的页面供给给客户端。SSG 适用于内容不经常改变的网站。
  • 服务器端烘托 (SSR): 服务器端烘托是 Next.js 在每个恳求上生成 HTML 的另一种办法。当用户拜访页面时,Next.js 获取数据并在服务器上出现 HTML,然后再将其发送到客户端。SSR 关于内容更新频频或用户体会个性化的网站很有用。
  • 增量静态重新生成 (ISR): ISR 是 Next.js 中的一项功用,它答应您按需静态生成页面,而不是在构建时。这意味着您的站点能够一起静态生成和动态生成。

现在咱们对 Next.js 中的服务器端烘托有了更好的了解,咱们能够持续下一节。

怎么增强 Next.js 代码库的模块化和可维护性

为了防止代码重复并增强代码的可重用性,您能够在 Next.js 项目中选用模块化的办法。经过将常用功用阻隔getAllCharacters在一个独自的模块中,您能够方便地在代码库的多个部分拜访和重用它们。

您能够在项目中进行快速调整。首要,导航到app/page.jsx文件并找到getAllCharacters顶部的函数。从文件中删除这个函数。

接下来,翻开文件并从那里lib/characters.js导出函数。getAllCharacters经过将函数移动到独自的模块,您能够轻松地在代码库的不同部分导入和运用它:

//  lib/characters.jsimport { endpoint } from '@/utils/endpoint'export async function getAllCharacters() {
 const data = await fetch(`${endpoint}/characters`)
​
 if (!data.ok) {
  throw new Error('Failed to fetch data')
  }
​
 return data.json()
}

现在让咱们getAllCharacters从中导入函数lib/characters.js并在内部运用它app/page.jsx

//  app/page.jsximport { getAllCharacters } from '@/lib/characters'export default async function Page() {
 const data = await getAllCharacters()
​
 return (
  <main>
    //content went here ...
  </main>
  )
}

这样,您将能够在整个代码库中拜访此获取功用。

怎么创立动态人物页面

祝贺您在本教程中达到了这一点!到目前为止,您现已对 Next.js 的基础常识有了深化的了解。

在本节中,您将创立一个动态 API 路由。此路途将使您能够独自获取每个人物的数据,并随后构建一个用户界面 (UI) 以向您的用户展现这些人物。

如安在 Next.js 中创立动态 API 路由

经过在 Next.js 中创立动态 API 路由,您能够依据人物的 slug 获取人物数据。为此,您需求运用方括号来命名您的文件夹,向 Next.js 标明这是一个动态路由。经过相应地命名文件夹,您能够在代码中拜访此动态值,然后答应您检索和显现所需人物的数据。

翻开api/characters/[slug]/route.js并增加以下代码段:

//  api/characters/[slug]/route.js export async function GET(req, { params }) {
 try {
  const character = characters.data.find(item => item.slug === params.slug)
​
  if (!character) {
   return new NextResponse('not found', { status: 404 })
   }
​
  const character_qoutes = qoutes.data.filter(
   item => item.character_id === character.id,
   )
​
  return NextResponse.json({
   character,
   character_qoutes: character_qoutes.length > 0 ? character_qoutes : null,
   })
  } catch (error) {
  return new NextResponse('Internal Server Error', { status: 500 })
  }
}

在上面的代码片段中,您有一个名为GET处理 Next.js API 路由中的 GET 恳求的异步函数。让咱们一步一步地分化它:

  1. 您运用 Next.js 文件系统(和)从它们各自的 JSON 文件中导入characters和数据。quotes``@/data/characters.json``@/data/quotes.json
  2. 该函数接收两个参数:(req代表传入的恳求)和一个目标params,该目标包括从恳求 URL 中提取的动态参数。
  3. characters在 try-catch 块内,代码检验经过将slug参数 fromparams与每个字符目标的特点进行比较来查找数据中的字符slug
  4. 假如未找到任何字符,代码将运用包NextResponse中的类回来状况代码为 404 的“未找到”呼应next/server
  5. 假如找到一个字符,代码将持续依据quotescharacter_id找到的字符的id.
  6. 过滤后的字符引号分配给character_quotes变量。
  7. 终究,代码运用 回来一个 JSON 呼应NextResponse.json(),包括character目标和character_quotes数组(或许null假如没有找到引号)。

Next.js 主动从 URL 中提取动态参数并使它们在params目标中可用。在此代码中,您slug运用拜访参数params.slug。这答应您从 URL 中检索特定字符的 slug,并运用它来查找数据中的相应字符characters

现在您能够检验此端点以查看成果,在浏览器中翻开http://localhost:3000/api/characters/peter-griffin,您应该能够看到以下 JSON 数据:

如何使用Next.js创建全栈应用程序
浏览器中的 JSON 数据

如安在 Next.js 中创立动态 UI 路由

现在您的 API 已设置并能够获取人物数据,是时分创立一个动态 UI 页面来展现此数据了。

创立动态 UI 页面的进程与您在设置动态 API 路由时所做的十分类似。但这一次,您将运用page.jsx而不是route.js生成 UI 路由。

翻开app/characters/[slug]/page.jsx并增加以下代码段:

//  app/characters/[slug]/page.jsximport { getAllCharacters } from '@/lib/characters'export const dynamicParams = falseexport async function generateStaticParams() {
 const { characters } = await getAllCharacters()
 return characters.map(character => ({ slug: character.slug }))
}
​
export async function getCharacterBySlug(slug) {
 const data = await fetch(`${endpoint}/characters/${slug}`)
​
 if (!data.ok) {
  throw new Error('Failed to fetch data')
  }
​
 return data.json()
}
​
export default async function Page({ params }) {
 const { character, character_qoutes } = await getCharacterBySlug(params.slug)
​
 return (
  <Container className="flex flex-col gap-5 py-5" as="main">
   <div className="flex flex-col gap-2">
    <h1 className="text-2xl font-semibold capitalize">{character.name}</h1>
    <ul className="flex gap-1 text-sm">
      {character.occupations.map(item => {
      return (
       <li
        key={item}
        className="p-2 text-gray-300 bg-gray-800 rounded-md"
       >
         {item}
       </li>
       )
      })}
    </ul>
   </div>
   <p className="text-sm leading-6">{character.description}</p>
   <ul className="grid gap-2 sm:grid-cols-2">
     {character.images.map(image => {
     return (
      <li
       key={image}
       className="relative flex overflow-hidden bg-gray-900 rounded-xl"
      >
       <Image
        className="transition-all duration-500 hover:scale-110 hover:rotate-2"
        src={image}
        alt=""
        width={760}
        height={435}
       />
      </li>
      )
     })}
   </ul>
    {character.skills && (
    <>
     <h2 className="text-xl font-bold">Power and Skills</h2>
     <ul className="flex flex-wrap gap-1">
       {character.skills.map(item => {
       return (
        <li
         className="flex justify-center flex-grow px-2 py-1 text-orange-400 rounded-full bg-orange-950"
         key={item}
        >
          {item}
        </li>
        )
       })}
     </ul>
    </>
    )}
    {character_qoutes && (
    <>
     <h2 className="text-xl font-bold">Famous Qoutes</h2>
     <ul className="grid gap-5">
       {character_qoutes.map((item, idx) => {
       return (
        <li
         className="p-2 italic text-gray-400 border-l-4 border-green-400 rounded-md"
         key={item.idx}
        >
          {item.qoute}
        </li>
        )
       })}
     </ul>
    </>
    )}
  </Container>
  )
}

不要被您在这儿看到的代码的长度吓到!乍一看,这好像势不可挡,但实际上十分简略。让咱们更深化地看看咱们在这段代码中做了什么:

Next.js 中有什么generateStaticParams

在 Next.js 中,该generateStaticParams函数用于指定应在构建时预烘托的动态路由。

为了更简略地解释它,让咱们假定您有一个包括多篇博文的网站,并且每篇博文都有一个仅有的 URL。运用generateStaticParams,您能够告诉 Next.js 在构建进程中应该生成和预出现哪些博客文章 URL。

当您完成 时generateStaticParams,您为其供给一个函数,该函数回来一个目标数组,标明您要预出现的动态途径。

每个目标一般包括一个与 URL 的动态部分相对应的参数。例如,假如您的博客文章具有/blog/post-1/blog/post-2等 URL,您将回来一个包括{ params: { slug: 'post-1' } }{ params: { slug: 'post-2' } }等目标的数组。

在咱们的例子中,咱们正在运用该函数检索字符列表getAllCharacters()。然后咱们映射字符并回来一个目标数组,每个目标都包括一个slug带有字符 slug 值的特点。

Next.js 然后将运用此信息在构建进程中为这些途径生成静态 HTML 文件。这答应页面作为静态文件供给,然后提高功能和 SEO。

dynamicParamsNext.js 生成静态页面的意图是什么?

在 Next.js 中,未运用生成的动态片段的行为generateStaticParamsdynamicParams.

dynamicParams设置为 时true,Next.js 将在拜访动态段时检验动态获取相应的页面。

另一方面,假如dynamicParams设置为false,Next.js 将在找不到恳求的页面时回来 404 页面。

此设置答应您界说 Next.js 怎么处理未预先生成的动态段,然后在处理应用程序中的动态路由时供给灵敏性。

怎么生成静态页面generateStaticParams

现在您现已成功地为每个人物生成了静态途径,让咱们看看怎么为每个人物获取数据。

getCharacterBySlug函数是一个异步函数,它接受slug参数,运用从指定的 API 端点获取数据fetch,并回来 JSON 格式的呼应数据。假如呼应不成功 ( !data.ok),则会抛犯过错。

组件将目标作为 propPage接收,其间包括从 URL 中提取的动态参数值。params它调用该getCharacterBySlug函数,传递从中提取的人物的 slugparams以获取特定人物的数据。

回来的数据然后用于填充 UI,其间包括显现人物的称号、职业、描绘、图画、力气和技能(假如可用)以及名言(假如可用)。

抱负情况下,您能够将其放入getCharacterBySlug内部lib/characters.js并从那里导出,但这由您决议!

如何使用Next.js创建全栈应用程序
到目前为止咱们的应用

怎么树立检验部分

祝贺您在本教程中达到了这一点!经过创立动态 API 路由和 UI 页面,并了解 Next.js 中的不同出现办法,您现已取得了很多成果。

现在,让咱们为这个应用程序增加一些交互性。在本节中,您将构建一个引人入胜的检验部分,用户能够在其间检验他们的 Family Guy 常识。

怎么创立 API 路由以检索随机问题

为确保每个用户都能获得令人兴奋和独特的体会,重要的是要防止每次都在检验中重复相同的问题。咱们期望保持新鲜感和吸引力。

为了完成这一点,咱们将施行一种机制,在用户每次开端检验时向他们提出不同的问题。

翻开app/api/quiz/random/route.js并增加以下代码段:

//  app/api/quiz/random/route.jsexport async function GET() {
 try {
  const random = Math.floor(Math.random() * questions.data.length)
  return NextResponse.json({
   randomQuestion: questions.data[random].id,
   })
  } catch (error) {
  return new NextResponse('Internal Server Error', { status: 500 })
  }
}

在此 Next.js API 路由中,您将完成从存储在名为 .json 文件中的一组问题中提取随机问题的逻辑quiz.jsonquestions首要,咱们从 JSON 文件中导入数据,NextResponse从 Next.js 服务器包中导入目标。

在函数内部GET,咱们运用Math.random()Math.floor()函数生成一个随机数。该数字用于从questions.data数组中挑选一个随机问题。咱们运用其索引检索问题,特别是id随机挑选问题的特点。

现在让咱们创立一个 UI 来运用这个随机问题。

怎么为检验创立介绍页面

您现在将为检验介绍部分创立一个用户界面 (UI)。此 UI 将作为用户在开端检验之前看到的初始屏幕。

您将利用刚刚创立的 API 路由在用户每次开端检验时动态地将用户重定向到一个新问题。

让咱们翻开app/quiz/page.jsx并增加以下代码:

//  app/quiz/page.jsxexport async function getRandomQuizQuestion() {
 const data = await fetch(`${endpoint}/quiz/random`, { cache: 'no-store' })
​
 if (!data.ok) {
  throw new Error('Failed to fetch data')
  }
​
 return data.json()
}
​
export default async function Page() {
 const data = await getRandomQuizQuestion()
​
 return (
  <Container
   as="main"
   className="flex flex-col gap-5 py-5 md:flex-row-reverse md:justify-between"
  >
   <div className="relative overflow-hidden rounded-2xl">
    <div className="md:w-[24rem]">
     <Image src="/wallpaper.jpg" alt="" width={700} height={700} />
    </div>
    <div className="absolute top-0 bottom-0 left-0 right-0 bg-gradient-to-t from-black to-transparent md:bg-gradient-to-r"></div>
   </div><div className="md:w-[50%] flex flex-col gap-5">
    <h1 className="text-2xl font-semibold">Family Guy Quiz</h1>
    <p className="text-sm leading-6 text-gray-300">
      Take this quiz to find out how much you know about the hit animated
      sitcom Family Guy. Test your knowledge of the characters, the
      episodes, and the show&apos;s many pop culture references.
    </p>
    <Link
     href={`/quiz/${data.randomQuestion}`}
     className="flex items-center justify-center gap-1 px-5 py-4 font-semibold text-orange-500 transition-colors rounded-md outline duration-600 hover:bg-orange-950"
    >
     <TbArrowBigRightFilled className="text-lg" />
      Take a Quiz Now!
    </Link>
   </div>
  </Container>
  )
}

此代码为检验介绍部分设置 UI,从 API 中获取随机问题,并为用户供给开端检验的按钮。

在此代码中,您或许现已注意到咱们将参数传递给办法的改变fetch{ cache: 'no-store' }

此更改含义严重,由于它确保咱们正在处理的页面不会运用静态站点生成 (SSG) 办法静态生成。相反,它会向供给的端点宣布 API 恳求,并在用户每次拜访该页面时获取新数据。

经过运用{ cache: 'no-store' },咱们禁用对此特定恳求的缓存。这确保每次用户拜访此页面时,都会获取一个新问题。

这种办法为检验体会增加了动态和交互元素,确保用户每次拜访页面时总是遇到不同的问题。

如何使用Next.js创建全栈应用程序
检验介绍页面

怎么为检验问题创立动态 API 路由

要供给动态检验问题,您需求创立一个新的 API 路由来获取并回来检验问题。这样,您能够动态检索问题并将其出现给用户。

翻开app/api/quiz/[id]并增加以下代码:

//  app/api/quiz/[id]export async function GET(req, { params }) {
 try {
  const question = questions.data.find(item => item.id === params.id)
​
  if (!question) {
   return new NextResponse('not found', { status: 404 })
   }
​
  const { correct_answer, ...rest } = question
​
  return NextResponse.json({
   question: rest,
   })
  } catch (error) {
  return new NextResponse('Internal Server Error', { status: 500 })
  }
}

在此 Next.js 路由中,您处理 GET 恳求以从检验中检索特定问题。您questions从 JSON 文件导入数据。运用恳求参数中供给的 ID,您能够查找匹配的问题。假如未找到问题,您将回来状况代码为 404 的“未找到”呼应。

假如找到问题,则提取正确答案并将剩下的问题详细信息存储在rest变量中。

终究,您回来包括问题详细信息(不包括正确答案)的 JSON 呼应。假如在此进程中发生任何过错,您将回来状况代码为 500 的“内部服务器过错”呼应。

现在,您能够经过翻开本地服务器http://localhost:3000/api/quiz/CfQnf3lH56在浏览器中检验此 API 路由:

如何使用Next.js创建全栈应用程序
http://localhost:3000/api/quiz/CfQnf3lH56

怎么创立动态 API 路由以获取答案

在完成 UI 之前,让咱们创立一个 API 路由,您能够在其间获取每个问题的正确答案。

翻开app/api/quiz/answer/[id]/route.js并向其间增加以下代码:

//  app/api/quiz/answer/[id]/route.jsexport async function GET(req, { params }) {
 try {
  const question = questions.data.find(item => item.id === params.id)
​
  if (!question) {
   return new NextResponse('not found', { status: 404 })
   }
​
  const { correct_answer } = question
​
  const filteredQuestions = questions.data.filter(
   item => item.id !== params.id,
   )
  const random = Math.floor(Math.random() * filteredQuestions.length)
​
  return NextResponse.json({
   correct: correct_answer,
   random: filteredQuestions[random].id,
   })
  } catch (error) {
  return new NextResponse('Internal Server Error', { status: 500 })
  }
}

此 API 路由的意图是依据供给的 ID 从检验中检索特定问题。该代码经过将给定 ID 与存储在数据中的问题 ID 进行比较来查找问题questions。假如找到恳求的问题,则提取其正确答案。

为了主张下一个问题,代码经过过滤将当前问题从可用问题池中移除。然后它会在剩下问题的范围内生成一个随机索引。运用这个随机索引,挑选一个新问题作为下一个问题的主张。

该代码构建并回来一个 JSON 呼应,其间包括所恳求问题的正确答案和随机挑选的下一个问题的 ID。此功用答应用户检索特定的检验问题并接收对以下问题的主张,然后改进检验的交互体会。

怎么为检验问题创立动态 UI 路由

现在您现已成功构建了一切必要的 API 端点,是时分采取下一步并创立一个用户界面 (UI) 以答应用户与您开发的 API 交互。此 UI 将作为用户拜访和运用您的 API 供给的功用的网关。

在本节中,您将了解 Next.js 中的动态服务器端烘托 (SSR)。咱们现已介绍了静态页面 (SSG),现在您将探究 SSR。SSR 也更容易施行。

翻开app/quiz/[id]/page.jsx并增加以下代码:

//  app/quiz/[id]/page.jsxasync function getQuizQuestion(id) {
 const data = await fetch(`${endpoint}/quiz/${id}`)
​
 if (!data.ok) {
  throw new Error('Failed to fetch data')
  }
​
 return data.json()
}
​
​
export default async function Page({ params }) {
 const { question } = await getQuizQuestion(params.id)
​
 return (
  <Container as="main" className="flex flex-col gap-5 py-5">
   <h1 className="text-lg font-semibold">{question.title}</h1>
   <Answer answers={question.answers} questionId={params.id} />
  </Container>
  )
}

此 Next.js 页面组件运用该函数从 API 端点获取问题数据getQuizQuestion。然后它运用 JSX 组件出现问题的标题和相应的答案。

如何使用Next.js创建全栈应用程序
路途用户界面问题

这便是烘托 Next.js 页面服务器端所需求做的一切!

鄙人一节中,您将创立一个客户端组件来处理用户与答案的交互。

如安在 Next.js 中创立客户端组件

在本教程的终究一部分,您将创立一个客户端组件来处理用户与答案的交互。

翻开components/Answer.jsx并增加以下代码:

//  components/Answer.jsx'use client'import { useEffect, useState } from 'react'
import cn from 'classnames'
import Link from 'next/link'
import { FiRepeat } from 'react-icons/fi'
import { MdNearbyError } from 'react-icons/md'
import { FaCheck } from 'react-icons/fa'export const Answer = ({ answers, questionId }) => {
 const [selected, setSeleceted] = useState(null)
 const [data, setData] = useState(null)
 const [loading, setLoading] = useState(false)
​
 useEffect(() => {
  let subscribed = true
  if (selected) {
   setLoading(true)
   fetch(`/api/quiz/answer/${questionId}`)
     .then(res => res.json())
     .then(data => {
     setLoading(false)
     if (subscribed) {
      setData(data)
      }
     })
   }
​
  return () => {
   console.log('cancelled!')
   subscribed = false
   }
  }, [questionId, selected])
​
 return (
  <>
   <ul className="grid grid-cols-2 gap-2 md:grid-cols-4">
     {answers.map(item => {
     const isLoading = selected === item && loading
     const isWrong =
      selected === item && data && data?.correct !== selected
     const isCorrect = data?.correct === item
​
     return (
      <li key={item}>
       <button
        disabled={data || loading}
        onClick={() => setSeleceted(item)}
        className={cn(
         'p-2 rounded-md  items-center justify-between w-full flex text-sm font-semibold disabled:cursor-not-allowed transition-all',
         isLoading && 'animate-pulse',
         isWrong ? 'bg-red-700' : 'bg-slate-800',
         isCorrect && 'outline text-green-500',
         )}
       >
         {item}
         {isCorrect && <FaCheck />}
         {isWrong && <MdNearbyError />}
       </button>
      </li>
      )
     })}
   </ul>
    {data?.random && (
    <Link
     href={`/quiz/${data.random}`}
     className="flex items-center gap-1 text-blue-400"
    >
     <FiRepeat className="mt-1" />
      Do it again
    </Link>
    )}
  </>
  )
}

这是一个带有两个道具的 React 组件:answersquestionId。它运用挂钩设置状况useState以盯梢所选答案、获取的数据和加载状况。

在组件内部,有一个钩子在or值更改useEffect时运转。假如存在答案,它会宣布 API 恳求以获取相应的数据并相应地更新状况。questionId``selected``selected``fetch

该组件运用映射函数出现答案选项列表。每个答案选项都标明为一个按钮。按钮的外观会依据所选答案、加载状况和答案的正确性进行修改。它还会依据所选答案的正确性显现不同的图标,例如复选符号或过错图标。

此外,假如获取的数据包括random特点,则会出现一个链接以运用新的随机问题重复检验。

这是咱们检验的终究版别的姿态:

如何使用Next.js创建全栈应用程序
检验终究版别

定论

这是完毕!您现已运用 Next.js 成功构建了您的第一个全栈应用程序。在本分步教程中,您学习了 Next.js 的基础常识,探究了其强大的功用并获得了创立现代 Web 应用程序所需的常识。

经过本教程,您不只构建了一个功用性应用程序,并且还获得了开端运用 Next.js 创立咱们自己的全栈应用程序的信心。您了解了路由、服务器端出现、API 集成等。

现在您在 Next.js 中有了坚实的基础,或许性是无限的。您能够持续探究高档主题,例如数据库集成、身份验证和布置,以使您的应用程序更上一层楼。

(NextJs教程:java567.com/search.html?sWord=next&v=2306015)