上篇搭建来基础配置,本篇来定义实体类。
在 Task.ts 中定义实体类,包含 id,标题,是否完成。
Task 将使用实体类:
作为客户端代码的模型类
作为服务器端代码的模型类
通过 remult 生成 API 端点、API 查询和数据库命令
我们正在创建的 Task 实体类将有一个自动生成的 UUIDid 字段,一个 title 字段和一个 completed 字段。实体的 API 路由(“任务”)将包括所有 CRUD 操作的端点。
定义模型
shared 在文件夹下创建一个文件夹 src。此文件夹将包含前端和后端之间共享的代码。
Task.ts 在文件夹中创建一个文件 src/shared/,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // src/shared/Task.ts import { Entity, Fields } from "remult"; @Entity("tasks", { allowApiCrud: true }) export class Task { @Fields.uuid() id!: string; @Fields.string() title = ''; @Fields.boolean() completed = false; }
在服务器的 api 模块中,通过将实体添加到您传递给方法的对象来向 TaskRemult 注册实体:entities: [Task]optionscreateRemultServer()
1 2 3 4 5 6 7 8 //src/server/api.ts import { createRemultServer } from "remult/server"; import { Task } from "../shared/Task"; export const api = createRemultServer({ entities: [Task] })
@Entity 装饰器告诉 Remult 这个类是一个实体类。装饰器接受一个 key 参数(用于命名 API 路由并作为默认数据库集合/表名称),以及一个 options 用于定义与实体相关的属性和操作的参数,将在本教程的下一节中讨论。
为了最初允许任务的所有 CRUD 操作,我们将选项 allowApiCrud 设置为 true。
装饰@Fields.uuid 器告诉 Remult 使用自动生成一个 id uuid。我们将此属性标记为可选,这样我们就可以创建新对象而无需首先 Task 分配一个对象,并让 Remult 在对象的数据存储到后端数据库之前生成一个对象。id
@Fields.string 装饰器告诉 Remult 该 title 属性是 type 的实体数据字段 String。此装饰器还用于定义与字段相关的属性和操作,将在本教程的下一节中讨论,属性@Fields.boolean 也是如此 completed。
建立一些测试数据 现在 Task 定义了实体,我们可以用它来为数据库准备一些测试数据。
将突出显示的代码行添加到 src/server/api.ts.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 // src/server/api.ts import { createRemultServer } from "remult/server"; import { Task } from "../shared/Task"; export const api = createRemultServer({ entities: [Task], initApi: async remult => { const taskRepo = remult.repo(Task); if (await taskRepo.count() === 0) { await taskRepo.insert([ { title: "Task a" }, { title: "Task b", completed: true }, { title: "Task c" }, { title: "Task d" }, { title: "Task e", completed: true } ]); } } })
在 initApi 建立数据库连接并且服务器准备好执行初始化操作之后,回调只会被调用一次。
taskRepo 是用于获取和创建实体对象的 Remult Repository 对象。Task
initApi 如果当前 count 为零,中的代码只是向数据库添加五个新任务。
保存更改将导致服务器重新启动并使用测试数据为数据库播种。tasks 在 http://localhost:3000/api/tasks 导航到 API 路由 (打开新窗口)查看数据。
我们首先将实体数据存储在后端 JSON 文件中。请注意,db 已在根文件夹下创建了一个 tasks.json 文件夹,其中包含一个包含创建的任务的文件。
显示任务列表 让我们通过在 React 组件中显示现有任务列表来开始开发 Web 应用程序。
将 的内容替换为 pages/index.tsx 以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 // pages/index.tsx import type { NextPage } from 'next' import { useEffect, useState } from 'react'; import { remult } from 'remult'; import { Task } from '../src/shared/Task'; async function fetchTasks() { return remult.repo(Task).find(); } const Home: NextPage = () => { const [tasks, setTasks] = useState<Task[]>([]); useEffect(() => { fetchTasks().then(setTasks); }, []); return ( <div> <main> {tasks.map(task => ( <div key={task.id}> <input type="checkbox" checked={task.completed} /> {task.title} </div> ))} </main> </div> ) } export default Home
以下是代码片段不同部分的快速概览:
该 fetchTasks 函数使用 Remult 存储库的 find 方法从服务器获取任务。 tasks 是一个任务数组 React 状态,用于保存任务列表。 React 的 useEffect hook 用于 fetchTasks 在 React 组件加载时调用一次。 浏览器刷新后,任务列表出现。
#添加样式 styles/globals.css 或者,通过使用此 CSS 文件替换 的内容,使应用看起来更好一些 (打开新窗口).
静态生成和服务器端渲染 Next.js 允许使用服务器端渲染 (SSR)或静态站点生成 (SSG)预渲染页面内容。
要从 getServerSideProp 或 getStaticProps 访问 remult 实例,您需要编写以下代码:
1 2 3 4 5 6 import { api } from '../src/server/api'; export const getServerSideProps: GetServerSideProps = async (context) => { const remult = await api.getRemult(context); return { props: {} }; };
然后您可以使用上面的代码片段获取数据 fetchTasks。
您的 pages/index.tsx 内容现在应该如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 import type { NextPage } from 'next' import { useEffect, useState } from 'react'; import { Task } from '../src/shared/Task'; import { api } from '../src/server/api'; type HomeProps = { tasks: Task[]; }; const Home: NextPage = ({ tasks }: HomeProps) => { return ( <div> <main> {tasks.map(task => ( <div key={task.id}> <input type="checkbox" checked={task.completed} /> {task.title} </div> ))} </main> </div> ) } export const getServerSideProps: GetServerSideProps = async (context) => { // Get remult instance const remult = await api.getRemult(context); // Find all tasks const tasks = await remult.repo(Task).find(); // Serialize tasks into plain object const tasksJson = JSON.parse(JSON.stringify(tasks)); return { props: { tasks: tasksJson } }; }; export default Home
注意 const tasksJson = JSON.parse(JSON.stringify(tasks));
在 Next.js 中,您只能使用以下方式将可序列化对象传递给 props:
JSON.parse(JSON.stringify(data)) entityRef 的 toApiJson()方法,或 使用库配置 nextjs next-superjson
实体建立完成,下篇讲下如何利用 Remult 实现分页、排序和过滤。