deno.com
本页内容

构建一个 Next.js 应用

Next.js 是一个流行的构建服务器端渲染应用程序的框架。它基于 React 构建,并提供了许多开箱即用的功能。

在本教程中,我们将构建一个简单的 Next.js 应用程序并使用 Deno 运行它。该应用将显示一个恐龙列表。当您点击其中一个时,它会将您带到恐龙页面,显示更多详细信息。

demo of the app

首先,请验证您已安装最新版本的 Deno,您需要至少 Deno 1.46.0

deno --version

使用 Deno 创建 Next.js 应用 跳到标题

Next 提供了一个 CLI 工具,可以快速搭建一个新的 Next.js 应用。在您的终端中运行以下命令,使用 Deno 创建一个新的 Next.js 应用

deno run -A npm:create-next-app@latest

当出现提示时,选择默认选项以使用 TypeScript 创建一个新的 Next.js 应用。

然后,cd 进入新创建的项目文件夹并运行以下命令安装依赖项

deno install

Next.js 存在一些仍然依赖 Object.prototype.__proto__ 的依赖项,因此您需要允许它。在一个新的 deno.json 文件中,添加以下行

{
  "unstable": ["unsafe-proto"]
}

现在您可以服务您的新 Next.js 应用了

deno task dev

这将启动 Next.js 服务器,点击输出链接到 localhost,在浏览器中查看您的应用。

添加后端 跳到标题

下一步是添加后端 API。我们将创建一个非常简单的 API,返回有关恐龙的信息。

我们将使用 Next.js 的内置 API 路由处理程序来设置我们的恐龙 API。Next.js 使用基于文件系统的路由,其中文件夹结构直接定义了路由。

我们将定义三个路由,第一个路由 /api 将返回字符串 Welcome to the dinosaur API,然后我们将设置 /api/dinosaurs 返回所有恐龙,最后 /api/dinosaur/[dinosaur] 返回基于 URL 中名称的特定恐龙。

/api/ 跳到标题

在您的新项目的 app 文件夹中,创建一个 api 文件夹。在该文件夹中,创建一个 route.ts 文件,它将处理对 /api/ 的请求。

将以下代码复制并粘贴到 api/route.ts 文件中

route.ts
export async function GET() {
  return Response.json("welcome to the dinosaur API");
}

此代码定义了一个简单的路由处理程序,它返回一个包含字符串 welcome to the dinosaur API 的 JSON 响应。

/api/dinosaurs 跳到标题

api 文件夹中,创建一个名为 dinosaurs 的文件夹。在该文件夹中,创建一个 data.json 文件,其中将包含硬编码的恐龙数据。将此 json 文件复制并粘贴到 data.json 文件中。

dinosaurs 目录中创建一个 route.ts 文件,它将处理对 /api/dinosaurs 的请求。在此路由中,我们将读取 data.json 文件并将恐龙作为 JSON 返回

route.ts
import data from "./data.json" with { type: "json" };

export async function GET() {
  return Response.json(data);
}

/api/dinosaurs/[dinosaur] 跳到标题

对于最后一个路由 /api/dinosaurs/[dinosaur],我们将在 dinosaurs 目录中创建一个名为 [dinosaur] 的文件夹。在其中,创建一个 route.ts 文件。在此文件中,我们将读取 data.json 文件,找到 URL 中名称对应的恐龙,并将其作为 JSON 返回

route.ts
import { NextRequest } from "next/server";
import data from "../data.json" with { type: "json" };

type RouteParams = { params: Promise<{ dinosaur: string }> };

export const GET = async (request: NextRequest, { params }: RouteParams) => {
  const { dinosaur } = await params;

  if (!dinosaur) {
    return Response.json("No dinosaur name provided.");
  }

  const dinosaurData = data.find((item) =>
    item.name.toLowerCase() === dinosaur.toLowerCase()
  );

  return Response.json(dinosaurData ? dinosaurData : "No dinosaur found.");
};

现在,如果您使用 deno task dev 运行应用程序并在浏览器中访问 https://:3000/api/dinosaurs/brachiosaurus,您应该会看到腕龙恐龙的详细信息。

构建前端 跳到标题

现在我们已经设置好后端 API,让我们构建前端来显示恐龙数据。

定义恐龙类型 跳到标题

首先,我们将设置一个新类型,以定义恐龙数据的形状。在 app 目录中,创建一个 types.ts 文件并添加以下代码

types.ts
export type Dino = { name: string; description: string };

更新主页 跳到标题

我们将更新 app 目录中的 page.tsx 文件,以从我们的 API 获取恐龙数据并将其显示为链接列表。

要在 Next.js 中执行客户端代码,我们需要在文件顶部使用 use Client 指令。然后我们将导入此页面所需的模块并导出将渲染页面的默认函数

page.tsx
"use client";

import { useEffect, useState } from "react";
import { Dino } from "./types";
import Link from "next/link";

export default function Home() {
}

Home 函数体内,我们将定义一个状态变量来存储恐龙数据,并定义一个 useEffect 钩子,以便在组件挂载时从 API 获取数据

page.tsx
const [dinosaurs, setDinosaurs] = useState<Dino[]>([]);

useEffect(() => {
  (async () => {
    const response = await fetch(`/api/dinosaurs`);
    const allDinosaurs = await response.json() as Dino[];
    setDinosaurs(allDinosaurs);
  })();
}, []);

在此之下,仍在 Home 函数体内,我们将返回一个链接列表,每个链接都指向恐龙的页面

page.tsx
return (
  <main>
    <h1>Welcome to the Dinosaur app</h1>
    <p>Click on a dinosaur below to learn more.</p>
    <ul>
      {dinosaurs.map((dinosaur: Dino) => {
        return (
          <li key={dinosaur.name}>
            <Link href={`/${dinosaur.name.toLowerCase()}`}>
              {dinosaur.name}
            </Link>
          </li>
        );
      })}
    </ul>
  </main>
);

创建恐龙页面 跳到标题

app 目录中,创建一个名为 [dinosaur] 的新文件夹。在此文件夹内创建一个 page.tsx 文件。此文件将从 API 获取特定恐龙的详细信息并将其渲染到页面上。

与主页非常相似,我们将需要客户端代码,并且我们将导入所需的模块并导出一个默认函数。我们将传入的参数传递给该函数并为该参数设置一个类型

[dinosaur]/page.tsx
"use client";

import { useEffect, useState } from "react";
import { Dino } from "../types";
import Link from "next/link";

type RouteParams = { params: Promise<{ dinosaur: string }> };

export default function Dinosaur({ params }: RouteParams) {
}

Dinosaur 函数体内,我们将从请求中获取选定的恐龙,设置一个状态变量来存储恐龙数据,并编写一个 useEffect 钩子,以便在组件挂载时从 API 获取数据

[dinosaur]/page.tsx
const selectedDinosaur = params.then((params) => params.dinosaur);
const [dinosaur, setDino] = useState<Dino>({ name: "", description: "" });

useEffect(() => {
  (async () => {
    const resp = await fetch(`/api/dinosaurs/${await selectedDinosaur}`);
    const dino = await resp.json() as Dino;
    setDino(dino);
  })();
}, []);

最后,仍在 Dinosaur 函数体内,我们将返回一个包含恐龙名称和描述的段落元素

[dinosaur]/page.tsx
return (
  <main>
    <h1>{dinosaur.name}</h1>
    <p>{dinosaur.description}</p>
    <Link href="/">🠠 Back to all dinosaurs</Link>
  </main>
);

运行应用程序 跳到标题

现在您可以使用 deno task dev 运行应用程序,并在浏览器中访问 https://:3000 查看恐龙列表。点击恐龙查看更多详情!

demo of the app

🦕 现在您可以使用 Deno 构建并运行 Next.js 应用了!要在此应用的基础上进行构建,您可以考虑添加数据库来替换您的 data.json 文件,或者考虑编写一些测试以使您的应用可靠并可用于生产环境。

您找到所需内容了吗?

隐私政策