arrays - 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}
</>
);
}
在这个代码块中我应该做些什么来实现这一点。
解决方案
推荐阅读
- rust - Rust 生命周期 - 书籍示例解决方案
- visual-studio - Visual Studio 2019 Live Unit Testing 显示 cmd 窗口
- solidity - 错误:无效地址(argument="address",value=undefined,code=INVALID_ARGUMENT,version=address/5.1.0)
- web - 是否可以将 NFC 芯片作为 Web 应用程序读取
- http - 使用 max-age=0 缓存的资源
- sql - 传递给 LEFT 或 SUBSTRING 函数的长度参数无效 我需要将颜色与数据分开
- wordpress - 如何检查验证码的正确实现
- oracle - 我们如何通过 PLSQL 逐行拆分 CLOB(有些行超过 32K 个字符)?
- flutter - Flutter Build 问题:突然为 Flutter App 构建 APK 失败
- json - 这是名为 'abc' 的 json 文件。我想访问文件之后我想访问 a,b,c,d,e,f 的值。如何以 groovy 语言访问?