Hooks error - Unable to create record with Prisma and NextJS

149 Views Asked by At

I have a create-t3-app built and I'm having trouble with hooks when creating records with Prisma. I'm trying to use a web form with two simple text fields to insert a record.

The full error seems to be related to the .create() function line const itemAdd = ...

Unhandled Runtime Error TypeError: hooks[lastArg] is not a function

I have also seen the error

Error: Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead.

** index.tsx **

import Head from "next/head";
import { api } from "~/utils/api";
import React, { FormEvent, ReactNode } from "react";

export default async function Home() {
  async function handleSubmit(e: FormEvent<HTMLFormElement>) {
    e.preventDefault();

    const formData = new FormData(e.currentTarget);

    /* THE hooks[lastArg] is not a function ERROR SEEMS TO COME UP AT THE .create() on the following line: */
    const itemAdd = await api.item.create({
      data: {
        name: (e.currentTarget.elements.namedItem("name") as HTMLInputElement)
          .value,
        isbn: (e.currentTarget.elements.namedItem("isbn") as HTMLInputElement)
          .value,
      },
      // include: { id: true }, // Returns all fields for all posts
    });

    console.log(itemAdd.id);
  }

  return (
    <>
      <Head>
        <title>lectura.io</title>
        <meta name="description" content="" />
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <main className="flex min-h-screen flex-col items-center justify-center">
        <div className="container flex flex-col items-center justify-center gap-12 px-4 py-16 ">
          <h1 className="text-5xl font-extrabold tracking-tight  sm:text-[5rem]">
            This is cool
          </h1>
        </div>
        <form onSubmit={handleSubmit}>
          <div className="container flex flex-col items-center justify-center gap-12 px-4 py-16 ">
            <div>
              name: <input type="text" name="name" className="border-2" />
            </div>
            <div>
              isbn: <input type="text" name="isbn" placeholder="isbn" />
            </div>
            <button type="submit">Submit</button>
          </div>
        </form>
      </main>
    </>
  );
}

** UPDATE: Adding the code for the ctx.db.item.create() below ** ** item.ts (router) **

import { z } from "zod";
import {
    createTRPCRouter,
    protectedProcedure,
    publicProcedure,
} from "~/server/api/trpc";
import { api } from "~/utils/api";

export const itemRouter = createTRPCRouter({
    getById: publicProcedure.input(z.string()).query(({ ctx, input }) => {
        return ctx.db.item.findFirst({
            where: {
                id: input,
            },
        });
    }),

    create: publicProcedure
        .input(
            z.object({
                name: z.string(),
                isbn: z.string(),
            }),
        )
        .mutation(async ({ ctx, input }) => {
            //const userId = ctx.session.user.id;
            try {
                const item = await ctx.db.item.create({
                    data: {
                        name: input.name,
                        isbn: input.isbn,
                    },
                });

                return item;
            } catch (error) {
                console.log(error);
            }
        }),
});

I have tried all combinations I can think of for async/await declarations/usage, and I've also tried the async function handleSubmit inside and outside of the Home() function.

Any help is greatly appreciated!

*** EDIT: Adding more code *** ** api.ts **

import { httpBatchLink, loggerLink } from "@trpc/client";
import { createTRPCNext } from "@trpc/next";
import { type inferRouterInputs, type inferRouterOutputs } from "@trpc/server";
import superjson from "superjson";

import { type AppRouter } from "~/server/api/root";

const getBaseUrl = () => {
  if (typeof window !== "undefined") return ""; // browser should use relative url
  if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`; // SSR should use vercel url
  return `http://localhost:${process.env.PORT ?? 3000}`; // dev SSR should use localhost
};

/** A set of type-safe react-query hooks for your tRPC API. */
export const api = createTRPCNext<AppRouter>({
  config() {
    return {
      transformer: superjson,
      links: [
        loggerLink({
          enabled: (opts) =>
            process.env.NODE_ENV === "development" ||
            (opts.direction === "down" && opts.result instanceof Error),
        }),
        httpBatchLink({
          url: `${getBaseUrl()}/api/trpc`,
        }),
      ],
    };
  },
  ssr: false,
});

export type RouterInputs = inferRouterInputs<AppRouter>;

export type RouterOutputs = inferRouterOutputs<AppRouter>;

** root.ts **

import { exampleRouter } from "~/server/api/routers/example";
import { createTRPCRouter } from "~/server/api/trpc";
import { itemRouter } from "./routers/item";

/**
 * This is the primary router for your server.
 * All routers added in /api/routers should be manually added here.
 */
export const appRouter = createTRPCRouter({
  example: exampleRouter,
  item: itemRouter,
});

// export type definition of API
export type AppRouter = typeof appRouter;
1

There are 1 best solutions below

0
SebastianK On

This looks like an error related to tRPC. If you are using mutation hooks, you must do it like so:

const { mutate } = trpc.urls.create.useMutation();

More info here.