▼环境(取自packege.json)
“@prisma/client”:“^4.11.0”
“@supabase/supabase-js”:“^2.12.1”
“next”:“^12.2.5”,.
“next-auth”:“^4.20.1”,.
“react”:“17.0.2”,“next”.
“ typescript ”:“第4.5.5条”
框架是NextJS
数据库是supabase
图像存储是数据库存储
ORM是Prisma
形式为反作用钩形
使用了typescript。
我可以在本地开发期间使用npm run dev注册,更新和检索图像,而不会出现任何问题。
如果我在本地运行npm run build而不是vercel,我可以毫无问题地构建,npm run start也没有任何问题。
要存储在DB中的图像的列类型是字符串。
我认为错误是因为next.js中定义的类型与prisma中保存时的类型不匹配,但我经验不足,很难确定原因并解决问题。
用www.DeepL.com/Translator翻译(免费版)
下面的错误消息仅在使用vercel构建时输出,我无法构建。
// Error output in vercel log
./pages/api/user/index.tsx:19:9
Type error: Type '{ name: any; email: any; password: any; image: any; }' is not assignable to type '(Without<UserCreateInput, UserUncheckedCreateInput> & UserUncheckedCreateInput) | (Without<...> & UserCreateInput)'.
Object literal may only specify known properties, and 'image' does not exist in type '(Without<UserCreateInput, UserUncheckedCreateInput> & UserUncheckedCreateInput) | (Without<...> & UserCreateInput)'.
错误API
- pages/API/user/index.tsx
import prisma from "../../../lib/prisma";
import type { NextApiRequest, NextApiResponse } from "next";
import { hash } from "bcrypt";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if (req.method === "POST") {
const { name, email, password, image } = req.body;
console.log(req.body);
const hash_password = await hash(password, 10);
const data = await prisma.user.create({
data: {
name: name,
email: email,
password: hash_password,
image: image,
},
});
return res.status(200).json(data);
} else if (req.method === "GET") {
const data = await prisma.user.findMany({});
return res.status(200).json(data);
}
}
调用上述API的组件
- pages/user/index.tsx
// pages/user/index.tsx
import { useForm } from "react-hook-form";
import { useRouter } from "next/router";
import Link from "next/link";
import { signIn } from "next-auth/react";
import Image, { StaticImageData } from "next/image";
import { useState, useRef } from "react";
import { supabase } from "../../lib/supabase";
// ユーザのデフォルト画像
const defaultImg = process.env.NEXT_PUBLIC_DEFAULT_IMG;
interface UserInput {
name: string;
email: string;
password: string;
image?: string | StaticImageData;
}
type uploadImageUrl = string;
export default function UserForm() {
const [uploadImageUrl, setUploadImageUrl] = useState<uploadImageUrl>();
const [uploadImageFile, setUploadImageFile] = useState<File>();
const router = useRouter();
const {
register,
handleSubmit,
formState: { errors },
} = useForm<UserInput>({
defaultValues: {
name: "",
email: "",
password: "",
image: defaultImg,
},
});
// const inputRef = useRef<HTMLInputElement>();
// 画像が選択されたら、プレビュー
const onChangeFile = (e: React.ChangeEvent<HTMLInputElement>) => {
const { files } = e.target;
setUploadImageUrl(URL.createObjectURL(files[0]));
setUploadImageFile(files[0]);
};
const submitUserRegister = async (input: UserInput) => {
//supabaseに画像をアップロード
const { data, error } = await supabase.storage
.from("photos")
.upload("user/" + uploadImageFile.name, uploadImageFile);
//supabaseから画像のURLをDL
const url = await supabase.storage
.from("photos")
.getPublicUrl(JSON.stringify(data));
const { publicUrl } = url.data;
// DLしたURLをimageに格納
const formData = {
name: input.name,
email: input.email,
password: input.password,
image: publicUrl,
};
try {
const res = await fetch("/api/user", {
method: "POST",
body: JSON.stringify(formData),
headers: {
"Content-Type": "application/json",
},
});
// json形式で返す
const data = await res.json();
const email = data.email;
//登録済みのデータを使用するとhash化したpasswordを利用してしまうため、formに入力されたpasswordを使用
const password = formData.password;
//sign In()でそのままログイン
await signIn("credentials", {
email,
password,
callbackUrl: "/",
redirect: true,
});
} catch (error) {
console.error("Error registering user:", error);
}
};
return (
<div>
<h3>ユーザー登録</h3>
<form
onSubmit={handleSubmit(submitUserRegister)}
className="w-full max-w-sm"
>
---
不要部分の為省略
---
<Image
src={uploadImageUrl ? uploadImageUrl : defaultImg}
width={100}
height={100}
></Image>
<label className="block mb-2 text-sm font-medium text-gray-900 dark:text-white">
Upload file
</label>
<input
className="block w-full text-sm text-gray-900 border border-gray-300 rounded-lg cursor-pointer bg-gray-50 dark:text-gray-400 focus:outline-none dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400"
id="file_input"
type="file"
onChange={onChangeFile}
/>
<div className="md:flex md:items-center">
<div className="md:w-2/3">
<button className="shadow bg-blue-500 hover:bg-blue-400 focus:shadow-outline focus:outline-none text-white font-bold py-2 px-4 rounded">
<Link href={`/`}>Home</Link>
</button>
</div>
<div className="md:w-2/3">
<button
className="shadow bg-blue-500 hover:bg-blue-400 focus:shadow-outline focus:outline-none text-white font-bold py-2 px-4 rounded"
type="submit"
>
Sign Up
</button>
</div>
</div>
</form>
</div>
);
}
schema.prisma
model User {
id String @default(cuid()) @id
name String?
email String? @unique
emailVerified DateTime?
image String?
password String
createdAt DateTime @default(now()) @map(name: "created_at")
updatedAt DateTime @updatedAt @map(name: "updated_at")
posts Post[]
@@map(name: "users")
}
如果您需要任何其他信息,请让我们知道。提前感谢您。
1条答案
按热度按时间uelo1irk1#
错误说图像字段不知道。也许你需要更新模型。尝试“prisma db push”。如果你在生产中,你需要使用prisma migrate来更新模型。如果你使用mondoDB,你也需要使用push,因为驱动程序不支持迁移。