首页 > 解决方案 > reactjs中的多个文件上传

问题描述

我有一个反应组件,其中有一个图像上传器。

    /* eslint-disable react/prop-types */
    import React from "react";
    import { Field, Form, FormikProps, Formik, FieldProps } from "formik";
    import { updateProvider } from "../../../request/provider";
    import {
      IProvider
    } from "../../../models/provider";
    import Loader from "../../../common/Loader";
    import ImageUploadCrop from "../../../common/ImageUploadCrop";
    import { Button } from "../../../common/Button";
    
    export function UpdateProvider({
      selectedProvider,
    }: {
      selectedProvider: IProvider | null;
    }): JSX.Element {
      const [isLoading, setIsLoading] = React.useState(true);
    
      if (isLoading) {
        return (
          <div className={"flex items-center justify-center"}>
            <Loader />
          </div>
        );
      }
    
      return (
        <div>
          {isLoading ? (
            <Loader />
          ) : (
            <Formik
              initialValues={{
                business_documents:
                  selectedProvider && selectedProvider.business_documents
                    ? selectedProvider.business_documents
                    : [],
              }}
              onSubmit={async (values, actions) => {
                try {
                  actions.setSubmitting(true);
                  setIsLoading(true);
                  const reqbody: any = {
                    business_documents: values.business_documents,
                  };
                  const res = await updateProvider(
                    reqbody,
                    selectedProvider?.slug + ""
                  );
    
                  if (res.status == 200) {
                    toast.success(res.data.message);
                    actions.setSubmitting(false);
                    setIsLoading(false);
                    await removeaSinglItem("updateProvider");
                    window.location.reload();
                  } else {
                    toast.error(res.data.message);
                  }
                } catch (err) {
                  console.log(err);
                  actions.setSubmitting(false);
                  setIsLoading(false);
                  toast.error("Failed to update provider");
                }
              }}
            >
              {(props: FormikProps<any>) => {
                return (
                  <Form>
                    <div className="flex items-center">
                      <div className="ml-8">
                        <ImageUploadCrop
                          title="Upload Business Documents ( Image of Trade License , etc )"
                          setFieldValue={(value: string) =>
                            props.setFieldValue("business_documents", value)
                          }
                          logo={props.values.business_documents}
                        />
                      </div>
<button
                              type="button"
                              onClick={() =>
                                props.setFieldValue("business_documents", [
                                  ...props.values.business_documents,
                                  
                                ])
                              }
                              className="float-right ml-4 text-sm underline"
                            >
                              Add Business Documents
                            </button>
                    </div>
                    <Button black type="submit" className="mt-6">
                      Submit
                    </Button>
                  </Form>
                );
              }}
            </Formik>
          )}
        </div>
      );
    }

此代码块始终发布单个图像 URL,但在我的请求正文中,我需要发送多个图像 URL 以发出有效的 POST 请求。我想要一个Add Image按钮,单击它时,另一个新ImageUploadCrop组件将添加到视图中,我可以在其中上传另一个图像等等。所以现在当我发布请求时,请求正文是 business_documents: ["https://s3-ap-southeast-1.amazonaws.com/media.evaly.com.bd/media/images/1f6b976e195d-newfile.jpeg"]

但我想将多个图像传递到这个business_documents数组中,比如

business_documents: ["https://s3-ap-southeast-1.amazonaws.com/media.evaly.com.bd/media/images/1f6b976e195d-newfile.jpeg", "https://s3-ap-southeast-1.amazonaws.com/media.evaly.com.bd/media/images/another-file.png"]

这是ImageUploadCrop组件

import React from "react";
import { AiFillCamera } from "react-icons/ai";
import { toast } from "react-toastify";
import { Modal } from "./Modal";
import ReactCrop from "react-image-crop";
import { uploadImageCore } from "../utils/image";
import { Button } from "./Button";
import "styled-components/macro";
import { BiEditAlt } from "react-icons/bi";
export default function ImageUploadCrop({
  title,
  setFieldValue,
  logo,
}: {
  title: string;
  setFieldValue: any;
  logo: string;
}): JSX.Element {
  const [state, setState] = React.useReducer(
    (s: any, a: any) => ({ ...s, ...a }),
    {
      profilePic: null,
      selected_image_ref: null,
      selected_image_src: null,
      crop: {
        aspect: 1 / 1,
        width: 350,
        locked: true,
        keepSelection: true,
      },
    }
  );
  const onFileSelected = async (event: any) => {
    const selectedFile = event.target.files[0];
    if (Math.floor(selectedFile.size / 1024) <= 4096) {
      const reader: any = new FileReader();
      reader.addEventListener(
        "load",
        () => {
          setState({ selected_image_src: reader.result });
        },
        false
      );
      reader.readAsDataURL(selectedFile);
    } else {
      toast({ message: "Image size must be less than 4MB", type: "info" });
    }
  };
  function getCroppedImg(image: any, crop: any, fileName: string) {
    const canvas = document.createElement("canvas");
    const scaleX = image.naturalWidth / image.width;
    const scaleY = image.naturalHeight / image.height;
    canvas.width = crop.width;
    canvas.height = crop.height;
    const ctx: any = canvas.getContext("2d");

    ctx.drawImage(
      image,
      crop.x * scaleX,
      crop.y * scaleY,
      crop.width * scaleX,
      crop.height * scaleY,
      0,
      0,
      crop.width,
      crop.height
    );

    return new Promise((resolve) => {
      canvas.toBlob((blob: any) => {
        blob.name = fileName; // eslint-disable-line no-param-reassign
        resolve(blob);
      }, "image/jpeg");
    });
  }
  const onImageLoaded = (image: HTMLImageElement): boolean => {
    setState({
      selected_image_ref: image,
    });
    return true;
  };

  return (
    <>
      <div className="">
        <label className="block mb-2">{title} </label>
        <label
          className="flex cursor-pointer"
          css={`
            width: 133.33px;
            height: 133.33px;
          `}
        >
          {/* <input
            className="absolute opacity-0 cursor-pointer "
            id="uploadFile"
            type="file"
            name="pic"
            onChange={onFileSelected}
            onClick={(event: any) => {
              event.target.value = null;
            }}
            title="Upload"
            accept="image/x-png,image/gif,image/jpeg"
          /> */}
          <input
            onChange={onFileSelected}
            id="uploadFile"
            name={"pic"}
            onClick={(event: any) => {
              event.target.value = null;
            }}
            type="file"
            accept="image/x-png,image/gif,image/jpeg"
            className="hidden"
          />
          <div
            className="relative overflow-hidden"
            css={`
              width: 133.33px;
              overflow: hidden;
              height: 133.33px;
              background-color: rgba(0, 0, 0, 0.12);
              border-radius: 50%;
              &:hover {
                > div {
                  display: block;
                }
              }
            `}
          >
            {/* <input
              className="absolute opacity-0 cursor-pointer "
              id="uploadFile"
              type="file"
              name="pic"
              onChange={onFileSelected}
              onClick={(event: any) => {
                event.target.value = null;
              }}
              title="Upload"
              accept="image/x-png,image/gif,image/jpeg"
            /> */}

            <div
              className="absolute rounded-full "
              css={`
                top: 0px;
                width: 133.33px;
                height: 133.33px;
                background-color: rgba(0, 0, 0, 0.12);
              `}
            >
              <div className="flex justify-center items-center w-full h-full">
                <div
                  className="bg-white rounded-full flex justify-center items-center"
                  css={`
                    width: 40px;
                    height: 40px;
                  `}
                >
                  <AiFillCamera size={25} />
                </div>
              </div>
            </div>
            {state.profilePic || logo ? (
              <div className="absolute">
                <img
                  src={state.profilePic || logo}
                  alt=""
                  css={`
                    width: 100%;
                    height: 100%;
                    margin: 0 auto;
                  `}
                />
                <div
                  className="absolute bottom-0 flex justify-center text-white p-1 w-full"
                  css={`
                    background: rgba(0, 0, 0, 0.4);
                  `}
                >
                  <BiEditAlt size={15} />
                </div>
              </div>
            ) : null}
          </div>
        </label>
      </div>
      {state.selected_image_src ? (
        <Modal
          close={() => {
            setState({
              uploading_image: false,
              selected_image_ref: null,
              selected_image_src: null,
              crop: {
                aspect: 1 / 1,
                width: 350,
                locked: true,
                keepSelection: true,
              },
            });
          }}
          header={() => "Update Picture"}
          modalContentWidth="40%"
          isActive={state.selected_image_src}
          renderBody={() => {
            return (
              <div
                className="p-4"
                style={{
                  display: "flex",
                  justifyContent: "center",
                  flexDirection: "column",
                }}
              >
                <div
                  className="rounded"
                  style={{
                    display: "flex",
                    justifyContent: "center",
                    background: "#f7fafc",
                  }}
                >
                  <ReactCrop
                    src={state.selected_image_src}
                    onImageLoaded={onImageLoaded}
                    crop={state.crop}
                    imageStyle={{ height: "auto", width: 400 }}
                    onChange={(newCrop: any) => setState({ crop: newCrop })}
                  />
                </div>
                <div className="flex justify-end py-2 mt-4">
                  <Button
                    style={{ width: "100%" }}
                    isLoading={state.uploading_image}
                    disabled={state.uploading_image}
                    onClick={() => {
                      getCroppedImg(
                        state.selected_image_ref,
                        state.crop,
                        "newFile.jpeg"
                      )
                        .then((croppedImageUrl) => {
                          setState({ uploading_image: true });
                          return uploadImageCore(croppedImageUrl);
                        })
                        .then((res) => {
                          setState({
                            profilePic: res.data.data.url,
                            uploading_image: false,
                            selected_image_ref: null,
                            selected_image_src: null,
                            crop: {
                              aspect: 1 / 1,
                              width: 350,
                              locked: true,
                              keepSelection: true,
                            },
                          });
                          setFieldValue(res.data.data.url);
                        })
                        .catch((error) => {
                          console.log(error);
                        });
                    }}
                    primary
                  >
                    Apply Crop
                  </Button>
                </div>
              </div>
            );
          }}
        />
      ) : null}
    </>
  );
}

在这个代码块中我应该做些什么来实现这一点。

标签: arraysreactjsformik

解决方案


推荐阅读