Antd uploader accepting all files despite giving the accept prop - reactjs

I am using antd drag and drop component https://ant.design/components/upload/#components-upload-demo-drag. In the example they have given if I add the prop accept it only accepts the restricted formats and do not add other files in the fileList. However when I use this component in my application, it adds all kinds of files. Why is this behavior occuring and how to avoid it?
const Uploader = () => {
const [files, setFiles] = useState([])
const onChangeHandler = (res) => {
setFiles(res.fileList)
};
console.log(files)
return (
<Upload.Dragger
accept=".pdf,.doc,.docx"
onChange={onChangeHandler}
showUploadList={false}
multiple
fileList={files}
>
Upload
</Upload.Dragger>
);
};
If I drag a png image for instance it does not get added in the fileList but if I manually select any file (which is in not in accept prop) it adds in state which I do not want. Any help?

You can combine with the prop beforeUpload (example in the documentation)
Example:
const Uploader = () => {
const types = ["application/pdf","application/vnd.openxmlformats-officedocument.wordprocessingm","application/msword"];
const [files, setFiles] = useState([])
const onChangeHandler = (res) => {
console.log(res);
let addFiles = true;
for(let i = 0; i < res.fileList.length; i++) {
if (!types.includes(res.fileList[i].type)) {
addFiles = false;
}
}
if( addFiles ) {
setFiles(res.fileList);
}
console.log(files);
};
return (
<Upload.Dragger
accept=".pdf,.doc,.docx"
beforeUpload={(file) => {
if (!types.includes(file.type)) {
message.error(`${file.name} is not a pdf, doc or docx file`);
return false;
} else {
return true
}
}}
onChange={onChangeHandler}
showUploadList={false}
multiple
fileList={files}
>
Upload
</Upload.Dragger>
);
};

Related

How to use PDF.JS with React?

I would like to parse a pdf file in a React app. The pdf will be provided through a html input.
I used pdf-parse - a wrapper around pdf.js in node - without any problem. But when it comes to React, I only receive this error:
MissingPDFException {message: 'Missing PDF "http://localhost:3000/myfile.pdf".', name: 'MissingPDFException'}
I upload the file like this:
export default function Home() {
const [data, setData] = useState();
const handleFile = (e) => {
const file = e.target.files[0];
const fileReader = new FileReader();
fileReader.onload = (d) => {
setData(new Uint32Array(d.target.result));
};
};
return (
<>
<h1>hello!</h1>
<input
type="file"
accept="application/pdf"
placeholder="insert PDF here"
onChange={(e) => handleFile(e)}
/>
<PDFViewer pdfFile={data} />
</>
);
}
And The file is supposed to be read here:
import * as PDFJS from "pdfjs-dist/build/pdf";
import * as pdfjsWorker from "pdfjs-dist/build/pdf.worker.entry";
window.PDFJS = PDFJS;
export default function PDFViewer({ pdfFile }) {
PDFJS.GlobalWorkerOptions.workerSrc = pdfjsWorker;
const getPDFDoc = useCallback(async () => {
const doc = await PDFJS.getDocument(pdfFile);
doc.promise.then(
(loadedPdf) => {
setPdfRef(loadedPdf);
},
function (reason) {
console.error(reason);
}
);
}, []);
useEffect(() => {
getPDFDoc();
}, [getPDFDoc]);
I doesn't seem to work at all. I have a custom config with webpack, typescript and SWC-loader. I have read all the related stackoverflow threads.
How to properly parse a PDF with PDF.js in React? If there is a better library, I'm open to any suggestions. My goal is not to display the pdf, but to get its content.
Your component only runs getPDFDoc on mount since pdfFile is missing in the usecallback deps, so when the file changes, it probably doesn't even notice as your effect won't re-run since getPDFDoc is referentially stable when it shouldn't be.
Try
import * as PDFJS from "pdfjs-dist/build/pdf";
import * as pdfjsWorker from "pdfjs-dist/build/pdf.worker.entry";
window.PDFJS = PDFJS;
export default function PDFViewer({ pdfFile }) {
PDFJS.GlobalWorkerOptions.workerSrc = pdfjsWorker;
const getPDFDoc = useCallback(async () => {
if (!pdfFile) return
const doc = await PDFJS.getDocument(pdfFile);
doc.promise.then(
(loadedPdf) => {
setPdfRef(loadedPdf);
},
function (reason) {
console.error(reason);
}
);
}, [pdfFile]);
useEffect(() => {
getPDFDoc();
}, [getPDFDoc]);
I think the reason for the weird "myfile.pdf" thing is probably because when it first runs pdfFile is not defined and this might be some internal library default. So I also added a guard to not do anything when it's not set.

upload component in antdesign

// I want to use the upload component of antDesing to accept only video files.
const beforeUpload = (file) => {
const isVideo = file.type === 'video/*'; //using (video/*) is not working here to accept any video file.
console.log('fle type', file.type);
if (!isVideo) {
message.error('You can only upload video file!');
}
const isLt10M = file.size / 1024 / 1024 < 10;
if (!isLt10M) {
message.error('Video must smaller than 10MB!');
}
return isVideo && isLt10M;
};
const handleChange = (info) => {
console.log('info', info);
};
render(
<Upload beforeUpload={beforeUpload} onChange={handleChange}>
<Button icon={<UploadOutlined />}>Click to Upload</Button>
</Upload>
)
//let me know if there is any way to sort the issue
Try it with regex:
const regex = /video\/.*/g;
const isVideo = regex.test(file.type);

How do I retain a file's name when converting to Base64?

I'm using "Input" to get files in a react app. I'm able to get a blob using readAsDataURL() but it's stripping out the file name and is replacing with "Data". When I log the blob I'm getting "data:image/jpeg;base64,/9j/4QAYRXhpZgAAS..." - "data" being the name that displays.
const handleGetFiles = (e) => {
const reader = new FileReader();
reader.readAsDataURL(e);
reader.onload = () => {
fileCollection((fileCollection) => [...fileCollection, {id: index, data: reader.result}]);
}
}
<Input
accept="image/*,video/*"
id="contained-button-file"
multiple type="file"
onChange={e => handleGetFiles(e)}
/>
Is there a way to use URL.createObjectURL(file) instead? I can't get that to work either.
The filename that you're looking for doesn't come from the FileReader API, but rather from the input element's files property.
You can expose the file in 2 ways from React:
Through a ref:
const Input = () => {
const inputEl = React.useRef();
const handleGetFiles = () => {
alert(inputEl.current.files[0].name)
};
return (
<input
...
onChange={handleGetFiles}
ref={inputEl}
/>
);
}
Through the event target
const Input = () => {
const handleGetFiles = (e) => {
alert(e.target.files[0].name)
};
return (
<input
...
onChange={handleGetFiles}
/>
);
}

How to solve the problem that the image is not visible when uploading an image inside React-Quill?

I'm working on a simple bulletin board with React-Quill. I'm implementing to communicate and save the content value to the server, but when uploading an image, there is an error that the image is not displayed in the content, so I can't solve it.
How can I solve this?
function Post() {
const QuillRef = useRef<ReactQuill>()
const [Title, setTitle] = useState("")
const [contents, setcontents] = useState("")
const imageHandler = () => {
const input = document.createElement("input");
const formData = new FormData();
input.setAttribute("type", "file");
input.setAttribute("accept", "image/*");
input.click();
input.onchange = async () => {
const file : any = input.files;
if (file !== null) {
formData.append("image", file[0]);
console.log(formData)
}
}
}
const titleHandler = (e : React.ChangeEvent<HTMLTextAreaElement>) => {
e.preventDefault()
setTitle(e.currentTarget.value)
}
return (
<div className="post">
<ReactQuill
style = {{height : "650px"}}
ref = {(element) => {
if(element != null) {
QuillRef.current = element
}
}}
value = {contents || ""}
onChange = {(content, delta, source, editor) => setcontents(editor.getHTML())}
modules = {modules}
formats = {formats}
theme = "snow"
placeholder = "내용을 입력해주세요"/>
</div>
);
}
export default Post;
If you check FormData with Console.log, it comes out as an empty object.

use Effect not being called as expected

I am trying to implement a simple file upload drop zone in React:
import { useState, useEffect } from 'react';
import './App.css';
const App = () => {
const [isDropzoneActive, setIsDropzoneActive] = useState(false);
const [files, setFiles] = useState([]);
const [currentChunkIndex, setCurrentChunkIndex] = useState(null);
const handleDragOver = e => {
e.preventDefault();
setIsDropzoneActive(true);
};
const handleDragLeave = e => {
e.preventDefault();
setIsDropzoneActive(false);
};
// Update the files array
const handleDrop = e => {
e.preventDefault();
setIsDropzoneActive(false);
// Just overwrite for this simple example
setFiles(e.dataTransfer.files);
};
// Monitor the files array
useEffect(() => {
if (files.length > 0) {
console.log('got a file');
setCurrentChunkIndex(0);
}
}, [files]);
// Monitor the chunk index
useEffect(() => {
if (currentChunkIndex !== null) {
readAndUploadCurrentChunk();
}
}, [currentChunkIndex]);
const readAndUploadCurrentChunk = () => {
// Implement later
};
return (
<div
onDragOver={handleDragOver}
onDragLeave={handleDragLeave}
onDrop={handleDrop}
className={"dropzone" + (isDropzoneActive ? " active" : "")}
>
{files.length > 0 ? 'Uploading' : 'Drop your files here'}
</div>
);
}
export default App;
However it seems that the effect that monitors [currentChunkIndex] is not being called correctly. I have attempted to drag files into the drop zone, one by one. [files] effect it called correctly each time but the effect on [currentChunkIndex] doesn't get called. What am I doing wrong here?
currentChunkIndex changes from null to 0, you set it only to 0.
useEffect(() => {
if (files.length > 0) {
console.log('got a file');
setCurrentChunkIndex(files.length);
}
}, [files]);

Resources