Vercel Blob 存储与 NextJS 14 服务器操作意外行为

问题描述 投票:0回答:1

我正在创建一个应用程序作为学习 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 发生变化。

next.js blob vercel
1个回答
0
投票

我设法让它发挥作用。

我做的第一件事是将服务器操作移动到其单独的文件中。


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>
  );
}
© www.soinside.com 2019 - 2024. All rights reserved.