我正在创建一个应用程序作为学习 NextJS 的爱好。 我目前正在尝试使用 Vercel Blob 存储,并且我已经能够使用其文档中列出的模板上传图像。
但是当我尝试创建自己的组件来使用它时,它有一些意想不到的行为。
我创建了一个包装器组件,它是一个服务器组件,以及一个具有表单的客户端组件。
EditImageModalWrapper.tsx
import { put } from "@vercel/blob";
import { revalidatePath } from "next/cache";
import EditImageModal from "./EditImageModal";
export default async function EditImageModalWrapper(props: {
isOpen: boolean;
onClose: () => void;
}) {
async function uploadImage(formData: FormData) {
"use server";
console.log("Server function called");
const imageFile = formData.get("image") as File;
const blob = await put(imageFile.name, imageFile, {
access: "public",
});
console.log(blob);
revalidatePath("/edit");
revalidatePath("/");
}
return (
<EditImageModal
isOpen={props.isOpen}
onClose={props.onClose}
serverAction={uploadImage}
/>
);
}
编辑图像模式
import {
Button,
Modal,
ModalBody,
ModalContent,
ModalFooter,
ModalHeader,
} from "@nextui-org/react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faArrowUpFromBracket } from "@fortawesome/free-solid-svg-icons";
import { useRef } from "react";
export default function EditImageModal(props: {
isOpen: boolean;
onClose: () => void;
serverAction: (formData: FormData) => void;
}) {
const fileInputRef = useRef<HTMLInputElement>(null);
const handleClick = () => {
if (fileInputRef.current) {
fileInputRef.current.click();
}
};
return (
<Modal isOpen={props.isOpen} onOpenChange={props.onClose} placement="auto">
<form action={props.serverAction}>
<ModalContent>
<ModalHeader className="flex flex-col gap-1">Edit Image</ModalHeader>
<ModalBody>
<div
className={`w-full h-64 flex justify-center items-center flex-col gap-4 font-bold hover:cursor-pointer border-2 border-dashed rounded-lg border-black`}
onClick={handleClick}
>
<FontAwesomeIcon
icon={faArrowUpFromBracket}
size="2x"
color="#222222"
/>
<span>Upload an image</span>
<input
ref={fileInputRef}
type="file"
accept="image/*"
id="image"
name="image"
style={{ display: "none" }}
/>
</div>
</ModalBody>
<ModalFooter className="flex justify-between">
<Button color="default" variant="bordered" onPress={props.onClose}>
Cancel
</Button>
<Button color="primary" type="submit">
Save
</Button>
</ModalFooter>
</ModalContent>
</form>
</Modal>
);
}
正如 Vercel 本身的文档所示,您可以将服务器操作作为 props 传递。但是,当我单击“提交”按钮时,我的页面将刷新,并且我的网址将变为 http://localhost:3000/?image=IMAGE_NAME.png。我的服务器 cli 或客户端 cli 中也没有收到任何日志。
有人知道为什么我会得到这个结果吗?
我尝试上传图像并从 blob 获取 url,但我的页面刷新并且我的 url 发生变化。
我设法让它发挥作用。
我做的第一件事是将服务器操作移动到其单独的文件中。
export async function uploadImage(formData: FormData): Promise<void> {
const image = formData.get("image") as File;
const blob = await put(image.name, image, {
access: "public",
});
console.log(blob);
revalidatePath("/edit");
revalidatePath("/");
}
然后我用表单将此服务器操作导入到我的文件中。
import {
Button,
Modal,
ModalBody,
ModalContent,
ModalFooter,
ModalHeader,
} from "@nextui-org/react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faArrowUpFromBracket } from "@fortawesome/free-solid-svg-icons";
import { useRef } from "react";
import { uploadImage } from "../../actions";
export default function EditImageModal(props: {
isOpen: boolean;
onClose: () => void;
serverAction: (formData: FormData) => void;
}) {
const fileInputRef = useRef<HTMLInputElement>(null);
const handleClick = () => {
if (fileInputRef.current) {
fileInputRef.current.click();
}
};
return (
<Modal isOpen={props.isOpen} onOpenChange={props.onClose} placement="auto">
<form action={uploadImage}>
<ModalContent>
<ModalHeader className="flex flex-col gap-1">Edit Image</ModalHeader>
<ModalBody>
<div
className={`w-full h-64 flex justify-center items-center flex-col gap-4 font-bold hover:cursor-pointer border-2 border-dashed rounded-lg border-black`}
onClick={handleClick}
>
<FontAwesomeIcon
icon={faArrowUpFromBracket}
size="2x"
color="#222222"
/>
<span>Upload an image</span>
<input
ref={fileInputRef}
type="file"
accept="image/*"
id="image"
name="image"
style={{ display: "none" }}
/>
</div>
</ModalBody>
<ModalFooter className="flex justify-between">
<Button color="default" variant="bordered" onPress={props.onClose}>
Cancel
</Button>
<Button color="primary" type="submit">
Save
</Button>
</ModalFooter>
</ModalContent>
</form>
</Modal>
);
}