nextjs学习第2期 - 集成convex

275 阅读2分钟

Convex 数据库是一个开源的响应式后端即服务(Backend-as-a-Service)平台,专为现代全栈应用开发设计。它集成了数据库、服务器函数、文件存储、实时同步、身份验证等功能,开发者只需编写 TypeScript 代码即可构建高性能、实时更新的应用。

集成convex

官方指南:docs.convex.dev/quickstart/…

安装依赖

pnpm install convex

运行convex

pnpm dlx convex dev

结束后项目根目录下会生成配置文件:.env.local ,并且看板会生成新的convex项目:

添加测试数据

这是一个测试

sampleData.jsonl

{"text": "Buy groceries", "isCompleted": true}
{"text": "Go for a swim", "isCompleted": true}
{"text": "Integrate Convex", "isCompleted": false}

将数据导入数据库:pnpm dlx convex import --table tasks sampleData.jsonl

创建查询请求:convex/tasks.ts

import { query } from "./_generated/server";

export const get = query({
  args: {},
  handler: async (ctx) => {
    return await ctx.db.query("tasks").collect();
  },
});

创建ConvexClientProvider

创建 app/providers/ConvexClientProvider.tsx

"use client";

import { ConvexProvider, ConvexReactClient } from "convex/react";
import { ReactNode } from "react";

const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!);

export function ConvexClientProvider({ children }: { children: ReactNode }) {
  return <ConvexProvider client={convex}>{children}</ConvexProvider>;
}

在 app/layout.tsx 中使用:

<ConvexClientProvider>
  {children}
</ConvexClientProvider>

展示数据

app/page.tsx

"use client";

import { useQuery } from "convex/react";
import { api } from "../../convex/_generated/api";

export default function Home() {
  const tasks = useQuery(api.tasks.get);
  return (
    <main className="flex min-h-screen flex-col items-center justify-between p-24">
      {tasks?.map(({ _id, text }) => <div key={_id}>{text}</div>)}
    </main>
  );
}

启动服务,发现数据显示在页面上,到此convex集成完毕,可以把测试数据删掉。

测试完就可以删除所有的数据。

添加表格

创建 convex/schema.ts 文件,所有的表格都定义在里面。

import { defineSchema, defineTable } from "convex/server";
import { v } from "convex/values";

export default defineSchema({
  // messages 表
  messages: defineTable({
    body: v.string(),
    user: v.id("users"),
  }),
  // users 表
  users: defineTable({
    name: v.string(),
    tokenIdentifier: v.string(),
  }).index("by_token", ["tokenIdentifier"]),
});

定义CRUD

创建 convex/files.ts 文件,针对 files 表进行增删改查操作。

convex 提供了 query 和 mutation 函数,query 只是用来查询操作,mutaion 则进行增删改。

以下是一个示例:

import { v } from "convex/values";
import { mutation, query } from "./_generated/server";

export const getFiles = query({
  args: {},
  handler: async (ctx, args) => {
    return await ctx.db.query("files").collect();
  },
});

export const create = mutation({
  args: {
    telegramFileId: v.string(),
    telegramMessageId: v.number(),
    name: v.string(),
    size: v.number(),
    type: v.string(),
  },
  handler: async (ctx, args) => {
    await ctx.db.insert("files", {
      telegramFileId: args.telegramFileId,
      telegramMessageId: args.telegramMessageId,
      name: args.name,
      size: args.size,
      type: args.type,
    });
  },
});

export const remove = mutation({
  args: {
    telegramMessageId: v.number(),
  },
  handler: async (ctx, args) => {
    const file = await ctx.db
      .query("files")
      .withIndex("by_telegramMessageId", (q) =>
        q.eq("telegramMessageId", args.telegramMessageId),
      )
      .unique();

    if (file) {
      await ctx.db.delete(file._id);
    }
  },
});

调用定义的CRUD

客户端调用

即声明了 use client 的地方调用。

查询使用 useQuery,增删改使用 useMutation。

查询操作:

const users = useQuery(api.users.get);

// 如果有参数的话
const users = useQuery(api.users.get, {
  id: xxx
});

修改操作:

const createUser = useMutation(api.users.create);

await createUser({ name: '张三', age: 12  });

服务端调用

服务端则使用 fetchMutation 和 fetchQuery。

await fetchMutation(api.files.remove, {
  telegramMessageId: Number(messageId),
});

更多操作还在探索