Reputation: 1
I am creating an application as a hobby to learn NextJS. I am currently trying to work with Vercel Blob storage and I have been able to upload images using the template listed in their documentation.
But when I try to create my own component to use it in, it has some unexpected behaviour.
I created a wrapper component that is a server component, and a client component with the form.
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}
/>
);
}
EditImageModal
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>
);
}
As docmented on Vercel itself, you can pass server actions as props. But when I click the submit button, my page refreshes and my url becomes http://localhost:3000/?image=IMAGE_NAME.png. I also don't get any logs in my server cli or my client cli.
Does someone know why I get this result?
I tried uploading an image and getting the url from the blob, but instead my page refreshes and my url changes.
Upvotes: 0
Views: 382
Reputation: 1
I managed to make it work.
The first thing I did was move the server action to its separate file.
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("/");
}
And then I imported this server action in my file with my form.
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>
);
}
Upvotes: 0