2022 年 8 月 24 日

使用 GraphQL、Prisma 和 React 实现端到端类型安全:前端

13 分钟阅读

端到端类型安全通过确保整个应用程序堆栈的类型保持同步来实现。

hero image prisma

目录

简介

在本系列中,您将学习如何使用 React、GraphQL、Prisma 和其他一些有用的工具将这三者联系起来,以实现端到端类型安全。

在本节中,您将构建一个小型 React 应用程序,该应用程序显示用户列表以及与每个用户关联的一组消息。此应用程序将是只读的,显示数据库中已存在的内容。

在第一篇文章中,应用程序将仅渲染静态数据,而不是从数据库中获取数据。在本系列的过程中,您将更改此设置并添加一个 GraphQL API 和一个数据库,您的应用程序可以消费它们以动态渲染其数据。

您将使用的技术

以下是您将在本系列中使用的主要工具

  • Prisma 作为对象关系映射器 (ORM)
  • PostgreSQL 作为数据库
  • Railway 用于托管您的数据库
  • TypeScript 作为编程语言
  • GraphQL Yoga 作为 GraphQL 服务器
  • Pothos 作为代码优先 GraphQL 模式构建器
  • Vite 用于管理和搭建您的前端项目
  • React 作为前端 JavaScript 库
  • GraphQL Codegen 用于根据 GraphQL 模式为前端生成类型
  • TailwindCSS 用于为应用程序设置样式
  • Render 用于部署您的 API 和 React 应用程序

先决条件

假设的知识

虽然本系列将尝试从初学者的角度详细介绍所有内容,但以下知识将有所帮助

  • JavaScript 或 TypeScript 的基本知识
  • GraphQL 的基本知识
  • React 的基本知识

开发环境

要跟随提供的示例,您需要具备

使用 Vite 启动 React 应用程序

在构建 React 应用程序时,有很多不同的入门方式。目前最简单和最流行的方式之一是使用 Vite 来搭建和设置您的应用程序。

要开始使用,请在您希望应用程序代码存放的目录中运行此命令

注意:您无需在运行此命令之前安装任何软件包。

此命令使用 TypeScript 模板在名为 react-client 的文件夹中设置一个随时可用的 React 项目。该模板开箱即用地配备了开发服务器、热模块替换和构建过程。

项目生成后,系统将提示您进入新目录、安装 node 模块并运行项目。继续并通过运行以下命令来执行此操作

开发服务器启动并运行后,您应该会看到类似于以下内容的输出

如果您打开该输出中的链接,您将看到 Vite 的 React 和 TypeScript 模板着陆页

清理模板

入门模板附带了一些您不需要的东西,因此首先要做的就是清理。

src 文件夹中,将删除两项内容。删除以下内容

  • App.css
  • /assets (整个目录)

接下来,将 /src/App.tsx 的内容替换为以下组件,以便为您自己提供一个干净的工作环境

设置 TailwindCSS

您的应用程序将使用 TailwindCSS 来简化组件的设计和样式设置。要开始使用,您首先需要一些新的依赖项

上面的命令将安装 TailwindCSS 在您的项目中工作所需的所有组件,包括 Tailwind CLI。使用新安装的 CLI 在您的项目中初始化 TailwindCSS

此命令在您的项目中创建了两个文件

  • tailwind.config.cjs:TailwindCSS 的配置文件
  • postcss.config.cjs:PostCSS 的配置文件

tailwind.config.cjs 中,您将看到一个 content 键。您可以在此处定义 TailwindCSS 在扫描您的代码并确定您正在使用哪些类和实用程序时应注意的项目中的哪些文件。这就是 TailwindCSS 确定需要捆绑到其构建和缩小输出中的内容的方式。

将以下值添加到 content 键的数组中,以告知 TailwindCSS 查看 src 文件夹中的任何 .tsx 文件

最后,在 src/index.css 中,您需要导入 TailwindCSS 实用程序,这是在您的项目中使用 TailwindCSS 所必需的。将整个文件的内容替换为以下内容

TailwindCSS 现在已配置完毕,可以使用了!将 src/App.tsx 中现有的 <h2> 标签替换为以下 JSX,以测试 TailwindCSS 类是否正常工作

如果您的网页看起来像这样,恭喜!您已成功设置 TailwindCSS!

注意:如果不是,请尝试重新启动开发服务器并确保正确遵循上述步骤。

定义和模拟您的数据

现在 TailwindCSS 已设置完毕,您几乎可以开始构建组件以显示您的数据了。您还需要做一件事:定义和模拟您的数据。

为了确保您的应用程序是类型安全的,您需要创建一组 TypeScript 类型来定义您的两个数据模型:用户和消息。构建这些类型后,您将模拟一组测试数据。

首先,在名为 src 的目录中创建一个名为 types.ts 的新文件

这是您将存储此应用程序所需的所有类型的文件。在该文件中,添加并导出一个新的 type,名为 Message,其中包含一个名为 bodystring 字段

此类型描述了 Message 对象中可用的内容。只有一个键,但在实际应用程序中,这可能包含数十个或更多字段定义。

接下来,添加并导出另一个名为 User 的类型,其中包含一个 name 字段(类型为 string)和一个 messages 字段(其中包含 Message 对象数组)

注意:在本系列的下一节中,您将用自动生成的类型替换这些手动编写的类型,这些类型包含 API 公开数据模型的最新表示形式。

现在您的数据已被“描述”,请转到 src/App.tsx。在这里,您将模拟一些数据以在您的应用程序中使用。

首先,将新的 User 类型导入到 src/App.tsx

接下来,在该文件中的 App 函数中,创建一个名为 users 的新变量,其中包含 User 对象数组,其中包含单个用户条目,该用户条目具有几个与之关联的消息

在上面的代码片段中,您定义了一个具有两条关联消息的单个用户。这就是您构建此应用程序 UI 组件所需的所有数据。

显示用户列表

您将构建的第一个 UI 组件是显示用户的组件。在 src 目录中创建一个名为 components 的新文件夹

在该文件夹内,创建一个名为 UserDisplay.tsx 的文件

此文件将包含用户显示组件。要启动该组件,请创建一个名为 UserDisplay 的函数,该函数现在返回一个简单的 <p> 标签。然后导出该函数

这将充当组件的骨架。这里的目标是允许此组件接收 user 参数并在组件内部显示该用户的数据。

要实现此目的,首先在 src/components/UserDisplay.tsx 的顶部导入您的 User 类型

您将使用此类型来描述 UserDisplay 函数中的 user 属性应包含的内容。

在此文件中添加一个名为 Props 的新 type,其中包含一个类型为 Useruser 字段。使用该类型来描述函数的参数(或“props”)

注意user 键在函数参数中被解构,以便轻松访问其值。

user 属性允许您为组件提供类型为 User 的对象。此应用程序中的每个用户都将显示在一个包含用户姓名的矩形中。

将现有的 <p> 标签替换为以下 JSX,以显示带有漂亮 TailwindCSS 样式的用户名

此组件现在已准备好显示用户的详细信息,但您尚未在任何地方渲染它。

转到 src/App.tsx 并导入您的新组件。然后,替换当前的 <h2> 标签,为您 users 数组中的每个用户渲染该组件

如果您回到浏览器,您应该会看到一个漂亮的框显示您的用户名!此时唯一缺少的是用户的消息。

显示每个用户的消息

现在您可以显示您的用户,您将显示用户关联的消息。您将创建一个类似“树视图”的内容来显示消息。

首先创建一个组件来显示单个消息。在 src/components 中创建一个名为 MessageDisplay.tsx 的新文件

然后,将 Message 类型从 src/types.ts 导入到新文件中,并创建一个包含两个键的 Props 类型

  • message:一个 Message 对象,其中包含消息详细信息
  • index:一个 number 值,其中包含来自父消息列表的当前消息的索引

结果应如下面的代码片段所示

有了这些部分,您就可以构建组件函数了。下面的代码使用您编写的 Props 类型来描述函数参数,使用解构提取 messageindex 值,在样式化的容器中渲染消息,最后导出组件

现在是时候使用该组件了!在 src/components/UserDisplay.tsx 中导入 MessageDisplay 组件,并为 user.messages 数组中的每个元素渲染一个组件

在您的浏览器中,您现在应该看到每个用户的消息在其右侧!

看起来很棒,但还有最后一件事要添加。您正在构建一个树视图,因此最后一部分是渲染将每条消息连接到其用户的“分支”。

src/components 中创建一个名为 Branch.tsx 的新文件

此组件将接收一个属性 trunk,该属性指示与其链接的消息是否是列表中的第一个。

注意:这就是您需要在 MessageDisplay 组件中使用 index 键的原因。

将以下组件插入到该文件中

上面的代码片段使用一些巧妙的 TailwindCSS 魔法渲染了一个分支。如果您对 TailwindCSS 提供的功能感兴趣,或者想更好地了解上面发生的事情,TailwindCSS 提供了出色的文档,其中涵盖了上面使用的所有类。

为了完成此应用程序的 UI,请在您的 MessageDisplay 组件中使用新的 Branch 组件,为每条消息渲染一个分支

回到您的浏览器中,您现在将看到每条消息的分支!将鼠标悬停在消息上以突出显示分支 ✨

总结 & 接下来

在本文中,您构建了完全类型安全的应用程序的前端部分。在此过程中,您

  • 设置了一个 React 项目
  • 设置 TailwindCSS
  • 建模并模拟了您的数据
  • 为您的应用程序构建了 UI 组件

此时,您的应用程序中的数据和类型是静态且手动构建的。在本系列的后续部分中,您将使用代码生成设置动态类型定义,并使用来自数据库的动态数据。

在下一篇文章中,您将开始构建您的 API,设置您的数据库,并在您的项目中初始化 Prisma。

不要错过下一篇文章!

订阅 Prisma 新闻通讯