reactjs 获取prisma数据并使用传递到react组件时出现打字错误

1hdlvixo  于 2023-05-06  发布在  React
关注(0)|答案(1)|浏览(133)

我使用的是typescript、next.js、react、trpc和prisma。在一个顶级组件中,我调用了一个trpc函数,该函数获取与另一个表具有多对多关系的表的所有行。在findMany函数中,我包含(连接)另一个表。在顶层组件( Jmeter 板)中,我成功地取回了数据,并将其Map到另一个组件(卡)。所有这些都是为了显示数据而“工作”的,没有任何东西在客户端上“中断”。但是,我确实有一个类型脚本错误,它破坏了我的部署linting。
错误:enter image description here
Jmeter 板组件:

import { type NextPage } from "next";
import React from "react";
import Card from "./Card";
import CreateNewCard from "~/components/CreateNewCard";
import { api } from "~/utils/api";
import type { Packet } from "./Card";

const Dashboard = (props: { organization_id: string }) => {
  const { data } = api.example.getAllUserPackets.useQuery({
    organization_id: props.organization_id,
  });

  return (
    <div className="min-w-screen flex min-h-screen">
      <div className="w-full">
        <div className="">Dashboard</div>
        <div className="flex flex-grow flex-wrap justify-evenly gap-8">
          <CreateNewCard />
          {!data ? (
            <div>Sorry there seems to be no projects for this organization</div>
          ) : (
            data.map((packet) => {
              //console.log("PACKET: ", packet);
              return <Card packet={packet} key={packet.id} />;
            })
          )}
        </div>
      </div>
    </div>
  );
};

export default Dashboard;

卡组件:

import Link from "next/link";
import { useState } from "react";
import { api } from "~/utils/api";
import toast from "react-hot-toast";
import { truncatedName } from "../helper/stringManipulations";

const Card = (props: { packet: Packet }) => {
  const [cardData, setCardData] = useState(props.packet);
  const [isEdittingTitle, toggleIsEditing] = useState(false);
  const {
    id,
    deadline,
    progress_indication,
    tags,
    is_priority_high,
    author_id,
    card_author_name,
  } = cardData;

  const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
    setCardData((prev) => {
      return {
        ...prev,
        [e.target.name]: e.target.value,
      };
    });
  };

  const { mutate, isLoading: isEditing } = api.example.editCard.useMutation({
    onSuccess: () => {
      // do somthing
    },
    onError: (e) => {
      const errorMessage = e.data?.zodError?.fieldErrors.content;

      if (errorMessage && errorMessage[0]) {
        toast.error(errorMessage[0], {
          duration: 3000,
          position: "top-center",
          // Custom Icon
          icon: "🙀",

          // Change colors of success/error/loading icon
          iconTheme: {
            primary: "#000",
            secondary: "#232323",
          },
        });
      } else {
        toast.error("Failed to post. Sorry, please post again later.", {
          duration: 3000,
          position: "bottom-center",
          // Custom Icon
          icon: "🙀",

          // Change colors of success/error/loading icon
          iconTheme: {
            primary: "#000",
            secondary: "#232323",
          },
        });
      }
    },
  });

  const deselect = () => {
    document.querySelector("p")?.toggleAttribute("focus");
  };

  return (
    <div
      onClick={(e) => {
        isEdittingTitle ? toggleIsEditing(false) : null;
      }}
      className="relative w-80 max-w-full content-end rounded-3xl bg-purple-500 px-8 py-4 text-white subpixel-antialiased shadow-xl hover:translate-y-1 hover:bg-purple-600 hover:shadow-sm"
    >
      <div className="max-w-md">
        <div className="flex justify-between">
          <div className="flex justify-between gap-4">
            <p className="font-bold">{is_priority_high && "High"} Priority</p>
          </div>

          <Link
            href="/packet/project-id"
            className="rounded-lg border px-4 py-2"
          >
            Go To Project
          </Link>
        </div>

        <div className="mt-2 flex flex-col">
          {!isEdittingTitle ? (
            <p
              onClick={(e) => {
                toggleIsEditing(!isEdittingTitle);
              }}
              className="edit-input w-full  overflow-visible whitespace-pre-wrap bg-transparent text-[26px] font-bold backdrop:max-h-min"
            >
              {cardData.title}
            </p>
          ) : (
            <textarea
              name="title"
              onFocus={(e) => e.target.select()}
              autoFocus={true}
              value={cardData.title}
              onKeyDown={(e) => {
                if (e.key === "Enter") {
                  mutate({ id, column: "title", content: cardData["title"] });
                  toggleIsEditing(!isEdittingTitle);
                }
              }}
              onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => {
                handleChange(e);
              }}
              className="resize-none bg-transparent text-[26px]"
            />
          )}

          <p className="">Created By: {card_author_name}</p>
          <div className="flex flex-row">
            <p className="pr-2 font-bold">Due</p>
            <p className=" ">{deadline?.toDateString()}</p>
          </div>

          <div className="py-6 text-[20px]">
            {!tags ? (
              <div></div>
            ) : (
              tags.map((tag) => {
                return <p key={tag.id}>{tag.tagName}</p>;
              })
            )}
          </div>
        </div>

        <div className="flex h-full w-full items-end justify-between">
          <div className="w-1/2">
            <p className="text-[20px] ">{progress_indication}</p>
          </div>

          <div className=" flex- flex w-2/6 justify-evenly gap-0 self-end">
            {/* {members.map((member) => {
              return (
                <Link key={member.name} href={`/team/${member.name.trim()}`}>
                  <div
                    className={` -mx-4 flex h-12 w-12 items-center justify-evenly gap-0 rounded-full hover:-translate-x-1 hover:-translate-y-1 ${member.color} p-2 text-xl`}
                  >
                    <p className={""}>{truncatedName(member.name)}</p>
                  </div>
                </Link>
              );
            })} */}
          </div>
        </div>
      </div>
    </div>
  );
};

export default Card;

export type Tag = {
  id: number;
  tagName: string;
};

export type Packet = {
  id: string;
  title: string;
  description: string;
  author_id: string;
  deadline: Date;
  createdAt: Date;
  updatedAt: Date;
  is_priority_high: boolean;
  progress_indication: string;
  card_author_name: string;
  organization_id: string;
  is_org_admin: boolean;
  tags: Tag[];
};

TRPC中的功能-查找共享用户“组织ID”的所有“数据包”

getAllUserPackets: publicProcedure
  .input(z.object({organization_id: z.string()}))
  .query(async ({ctx, input}) => {

    const data = await ctx.prisma.packet.findMany({where: {organization_id: input.organization_id}, include: {tags: true}} )

    return data
  }),

Prisma型号

model Packet {
  id                  String   @id @default(cuid())
  createdAt           DateTime @default(now())
  updatedAt           DateTime @updatedAt
  card_author_name    String?
  author_id           String
  organization_id     String
  is_org_admin        Boolean? @default(false)
  title               String
  description         String
  project_leader_id   String?
  progress_indication Progress @default(CREATED)
  is_priority_high    Boolean? @default(false)
  deadline            DateTime @default(now())
  tags                Tag[]

  @@index([author_id])
}

model Tag {
  id      String   @id @default(cuid())
  tagName String
  packet  Packet[]
}

我尝试添加反映数据的类型(在Card Component的底部看到),并确保数据库中可能需要的数据不会因“不在前端”而导致问题。我给出了Card组件及其期望的 prop ,以及Card JSX如何在Dashboard组件中接收数据。
我对 typescript 和Prisma的不熟悉是罪魁祸首,但感谢任何帮助学习我在这里错过了什么。

luaexgnf

luaexgnf1#

您不应该手动为prisma.schema模型创建类型,因为Prisma会自动或使用npx prisma generate命令手动创建它们。
因此,要解决这个问题,您需要从Card.tsx中删除已经手动定义的类型,并从@prisma/client中导入自动创建的类型。由于Prisma Client不会自动处理类型中的关系,因此您需要使用以下代码来使其工作:

// Card.tsx

import { Prisma } from '@prisma/client';

const packetWithTags = Prisma.validator<Prisma.UserArgs>()({
  include: { tags: true },
})

type PacketWithTags = Prisma.UserGetPayload<typeof packetWithTags>
  • https://github.com/prisma/prisma/issues/12022#issuecomment-1050646465
  • https://www.prisma.io/docs/concepts/components/prisma-client/advanced-type-safety/operating-against-partial-structures-of-model-types#problem-using-variations-of-the-generated-model-type

然后你可以使用类型PacketWithTags作为你的组件props类型Card.tsx:)

相关问题