antd:上传 `value` 不是有效的 prop,您的意思是 `fileList` 吗?错误组件堆栈

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

我必须在ant design中使用uplaod,但在浏览器控制台中next.js应用程序出现错误。

enter image description here

这是我的表单提交代码。

"use client";
import {
  Form,
  Upload,
  Input,
  Select,
  Typography,
  Image,
  Button,
  message,
  Row,
  Col,
  Divider,
  Spin,
} from "antd";
import TextArea from "antd/es/input/TextArea";
import React, { useEffect, useState } from "react";
import { InboxOutlined, PlusOutlined, ProductFilled } from "@ant-design/icons";
import SupplierPageTitle from "@/components/supplier/SupplierPageTitle.js";
import useAuthGuard from "@/utils/useAuthGuard.js";
import { AddNewProduct } from "@/services/productService.js";
import { fetchProductCategories } from "@/services/productCategoryService.js";
import SupplierPageContainer from "@/components/supplier/SupplierPageContainer";
import useNotification from "@/utils/useNotification";
import { LoadingOutlined } from "@ant-design/icons";
import "./styles.css";

const { Title } = Typography;

const getBase64 = (file) =>
  new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = () => resolve(reader.result);
    reader.onerror = (error) => reject(error);
  });

const AddProduct = () => {
  const [previewOpen, setPreviewOpen] = useState(false);
  const [categories, setCategories] = useState([]);
  const [previewImage, setPreviewImage] = useState("");
  const [fileList, setFileList] = useState([]);
  const [videoFile, setVideoFile] = useState(null);
  const [uploading, setUploading] = useState(false);
  const [loading, setLoading] = useState(false);
  const { openNotification, contextHolder } = useNotification();
  const [form] = Form.useForm();

  const { user } = useAuthGuard({ middleware: "auth" });

  const handlePreview = async (file) => {
    if (!file.url && !file.preview) {
      file.preview = await getBase64(file.originFileObj);
    }
    setPreviewImage(file.url || file.preview);
    setPreviewOpen(true);
  };

  const handleImageChange = ({ fileList: newFileList }) => {
    if (newFileList.length > 6) {
      openNotification("error", "Error", "You can only upload up to 6 images!");
    } else {
      setFileList(newFileList);
    }
  };

  const onFinish = async (values) => {
    try {
      if (!fileList || fileList.length !== 6) {
        openNotification("error", "Error", "Please upload at least 6 images.");
        return;
      }

      const seoTagsArray = values.seoTags
        ?.split(",")
        .map((tag) => tag.trim())
        .filter((tag) => tag !== "");

      if (!seoTagsArray || seoTagsArray.length === 0) {
        openNotification(
          "error",
          "Error",
          "Please provide valid SEO tags as comma-separated values."
        );
        return;
      }

      const formData = new FormData();

      fileList.forEach((file, index) => {
        formData.append("images", file.originFileObj, `image${index}.jpg`);
      });

      if (videoFile) {
        formData.append("videoFile", videoFile);
      }

      formData.append("productName", values.productName);
      formData.append("description", values.description);
      formData.append("stockQuantity", values.stockQuantity);
      formData.append("wholesalePrice", values.WholePrice);
      formData.append("retailPrice", values.RetailPrice);
      formData.append("seoTags", JSON.stringify(seoTagsArray));
      formData.append("supplier", user?.id);
      formData.append("category", values.productCategory);

      setLoading(true);
      await AddNewProduct(formData);
      openNotification("success", "Success", "Product added Successfully");
      form.resetFields();
      setFileList([]);
    } catch (error) {
      console.error("Error uploading product:", error);
      openNotification(
        "error",
        "Error",
        "An unexpected error occurred while uploading product"
      );
    } finally {
      setLoading(false);
    }
  };

  const fetchCategories = async () => {
    try {
      const result = await fetchProductCategories();
      setCategories(result);
    } catch (error) {
      console.error("Error fetching categories:", error);
      openNotification("error", "Error", "Failed to fetch categories.");
    }
  };

  useEffect(() => {
    fetchCategories();
  }, []);

  const uploadButton = (
    <button
      style={{
        border: 0,
        background: "none",
      }}
      type="button"
    >
      <PlusOutlined />
      <div
        style={{
          marginTop: 8,
        }}
      >
        Upload
      </div>
    </button>
  );

  return (
    <>
      {contextHolder}

      <Row gutter={[16, 16]} justify="start">
        <Col xs={24} sm={12} md={12} lg={12} xl={12}>
          <SupplierPageTitle
            icon={<ProductFilled />}
            pageTitle="Add new Product"
          />
        </Col>

        <Col span={24}>
          <Divider />
        </Col>
      </Row>
      <SupplierPageContainer
        childern={
          <Row gutter={[16, 16]} justify="start">
            <Col span={24} style={{ position: "relative" }}>
              <Spin
                spinning={loading}
                indicator={
                  <LoadingOutlined
                    style={{
                      fontSize: 48,
                    }}
                    spin
                  />
                }
                style={{
                  position: "absolute",
                  top: "40%",
                }}
                size="large"
              >
                <div className={loading ? "blur-effect" : ""}>
                  <Form
                    form={form}
                    labelCol={{ span: 8 }}
                    wrapperCol={{ span: 16 }}
                    layout="horizontal"
                    style={{ maxWidth: 1000 }}
                    onFinish={onFinish}
                  >
                    <Form.Item
                      label="Product Name"
                      name="productName"
                      rules={[
                        {
                          required: true,
                          message: "Please input product name!",
                        },
                      ]}
                    >
                      <Input />
                    </Form.Item>
                    <Form.Item
                      label="Description"
                      name="description"
                      rules={[
                        { required: true, message: "Please fill description!" },
                      ]}
                    >
                      <TextArea rows={4} />
                    </Form.Item>
                    <Form.Item
                      label="Stock Quantity"
                      name="stockQuantity"
                      rules={[
                        {
                          required: true,
                          message: "Please input stock quantity!",
                        },
                        {
                          validator: (_, value) => {
                            if (!value) {
                              return Promise.reject(
                                new Error("Stock quantity is required.")
                              );
                            }
                            if (!/^\d+$/.test(value)) {
                              return Promise.reject(
                                new Error(
                                  "Stock quantity must be a valid integer."
                                )
                              );
                            }
                            return Promise.resolve();
                          },
                        },
                      ]}
                    >
                      <Input />
                    </Form.Item>
                    <Form.Item
                      label="Whole Sale Price"
                      name="WholePrice"
                      rules={[
                        { required: true, message: "Please input price!" },
                        {
                          validator: (_, value) => {
                            if (!value) {
                              return Promise.reject(
                                new Error("Wholesale price is required.")
                              );
                            }
                            if (!/^\d+(\.\d{1,2})?$/.test(value)) {
                              return Promise.reject(
                                new Error(
                                  "Wholesale price must be a valid float (e.g., 100.00, 999.99)."
                                )
                              );
                            }
                            return Promise.resolve();
                          },
                        },
                      ]}
                    >
                      <Input />
                    </Form.Item>
                    <Form.Item
                      label="Retail Price"
                      name="RetailPrice"
                      rules={[
                        {
                          required: true,
                          message: "Please input retail price!",
                        },
                        {
                          validator: (_, value) => {
                            if (!value) {
                              return Promise.reject(
                                new Error("Retail price is required.")
                              );
                            }
                            if (!/^\d+(\.\d{1,2})?$/.test(value)) {
                              return Promise.reject(
                                new Error(
                                  "Retail price must be a valid float (e.g., 100.00, 999.99)."
                                )
                              );
                            }
                            return Promise.resolve();
                          },
                        },
                      ]}
                    >
                      <Input />
                    </Form.Item>
                    <Form.Item
                      label="Product Category"
                      name="productCategory"
                      rules={[
                        { required: true, message: "Please select category!" },
                      ]}
                    >
                      <Select
                        showSearch
                        placeholder="Search to Select"
                        optionFilterProp="label"
                        filterSort={(optionA, optionB) =>
                          (optionA?.label ?? "")
                            .toLowerCase()
                            .localeCompare((optionB?.label ?? "").toLowerCase())
                        }
                        options={categories.map((category) => ({
                          value: category.categoryId,
                          label: category.categoryName,
                        }))}
                      />
                    </Form.Item>
                    <Form.Item
                      label="SEO Tags"
                      name="seoTags"
                      rules={[
                        { required: true },
                        {
                          validator: (_, value) => {
                            if (!value || value.trim() === "") {
                              return Promise.reject(
                                new Error("SEO tags cannot be empty.")
                              );
                            }

                            const seoTagsArray = value
                              .split(",")
                              .map((tag) => tag.trim())
                              .filter((tag) => tag !== "");

                            if (seoTagsArray.length === 0) {
                              return Promise.reject(
                                new Error(
                                  "Please provide at least one valid tag."
                                )
                              );
                            }

                            return Promise.resolve();
                          },
                        },
                      ]}
                    >
                      <TextArea
                        rows={4}
                        placeholder="Add SEO tags as comma-separated values. eg: tag1, tag2, tag3"
                      />
                    </Form.Item>
                    <Form.Item label="Product Images" name="images">
                      <div>
                        <Upload
                          listType="picture-card"
                          fileList={fileList}
                          onPreview={handlePreview}
                          onChange={handleImageChange}
                          beforeUpload={(file) => {
                            const isJpgOrJpeg =
                              file.type === "image/jpeg" ||
                              file.type === "image/jpg" ||
                              file.type === "image/png";
                            const isLt2M = file.size / 1024 / 1024 < 2;

                            if (!isJpgOrJpeg) {
                              message.error(
                                "Only JPG/JPEG/PNG images are allowed!"
                              );
                              return Upload.LIST_IGNORE;
                            }

                            if (!isLt2M) {
                              message.error("Image must be smaller than 2MB!");
                              return Upload.LIST_IGNORE;
                            }

                            return true;
                          }}
                        >
                          {fileList.length < 6 ? uploadButton : null}
                        </Upload>
                        {previewImage && (
                          <Image
                            wrapperStyle={{ display: "none" }}
                            preview={{
                              visible: previewOpen,
                              onVisibleChange: (visible) =>
                                setPreviewOpen(visible),
                              afterOpenChange: (visible) =>
                                !visible && setPreviewImage(""),
                            }}
                            alt="gmart.com"
                            src={previewImage}
                          />
                        )}
                      </div>
                    </Form.Item>

                    <Form.Item label="Product Video" name="video">
                      <Upload.Dragger
                        name="file"
                        beforeUpload={(file) => {
                          const isMp4 = file.type === "video/mp4";
                          if (!isMp4) {
                            message.error("You can only upload MP4 files!");
                            return Upload.LIST_IGNORE;
                          }
                          const isLt20MB = file.size / 1024 / 1024 < 20;
                          if (!isLt20MB) {
                            message.error("Video must be smaller than 20MB!");
                            return Upload.LIST_IGNORE;
                          }
                          setVideoFile(file);
                          return false;
                        }}
                        maxCount={1}
                      >
                        <p className="ant-upload-drag-icon">
                          <InboxOutlined />
                        </p>
                        <p className="ant-upload-text">
                          Click or drag video file to this area to upload
                        </p>
                      </Upload.Dragger>
                    </Form.Item>
                    <Form.Item
                      style={{ display: "flex", justifyContent: "flex-end" }}
                    >
                      <Button
                        type="primary"
                        htmlType="submit"
                        loading={uploading}
                        style={{ width: 150 }}
                      >
                        {uploading ? "Uploading..." : "Add Product"}
                      </Button>
                    </Form.Item>
                  </Form>
                </div>
              </Spin>
            </Col>
          </Row>
        }
      />
    </>
  );
};

export default AddProduct;

这是代码中图片文件列表上传部分。

<Form.Item label="Product Images" name="images">
                      <div>
                        <Upload
                          listType="picture-card"
                          fileList={fileList}
                          onPreview={handlePreview}
                          onChange={handleImageChange}
                          beforeUpload={(file) => {
                            const isJpgOrJpeg =
                              file.type === "image/jpeg" ||
                              file.type === "image/jpg" ||
                              file.type === "image/png";
                            const isLt2M = file.size / 1024 / 1024 < 2;

                            if (!isJpgOrJpeg) {
                              message.error(
                                "Only JPG/JPEG/PNG images are allowed!"
                              );
                              return Upload.LIST_IGNORE;
                            }

                            if (!isLt2M) {
                              message.error("Image must be smaller than 2MB!");
                              return Upload.LIST_IGNORE;
                            }

                            return true;
                          }}
                        >
                          {fileList.length < 6 ? uploadButton : null}
                        </Upload>
                        {previewImage && (
                          <Image
                            wrapperStyle={{ display: "none" }}
                            preview={{
                              visible: previewOpen,
                              onVisibleChange: (visible) =>
                                setPreviewOpen(visible),
                              afterOpenChange: (visible) =>
                                !visible && setPreviewImage(""),
                            }}
                            alt="gmart.com"
                            src={previewImage}
                          />
                        )}
                      </div>
                    </Form.Item>

如何调试此类错误。我也遵循了 ant design 文档,但没有任何线索。指导我如何一步一步解决这个问题

javascript reactjs file-upload antd next.js13
1个回答
0
投票

通过将此行添加到 Form.Item , valuePropName={"filelist"} 解决了该错误。在 Form.Item 内部使用上传组件时需要传递上述值。

© www.soinside.com 2019 - 2024. All rights reserved.