I really need your help with uploading files using Ant Design (antd). I don't need request action with upload component, therefore I use the onSuccess() function in customRequest to skip fetch, but onChange method the status stucks only on 'uploading'. It doesn't go to 'done' status. I need your help, please
Sandbox link: https://codesandbox.io/s/runtime-platform-znyow?file=/src/App.js
import React, { useState } from "react";
import "./styles.css";
import { Button, Upload } from "antd";
export default function App() {
const [fileList, setFileList] = useState([]);
const fileProps = {
action: "",
name: "file",
multiple: true,
customRequest(e) {
e.onSuccess();
},
onChange(info) {
const { status } = info.file;
console.log(status); // always 'uploading'
if (status === "done") {
// this part is unreachable
let fileList = [...info.fileList];
setFileList(fileList);
}
},
onRemove: (file) => {
setFileList((prevState) => prevState.filter((d) => d.uid !== file.uid));
}
};
return (
<div className="App">
<Upload {...fileProps} fileList={fileList}>
<Button type="primary">Attach file</Button>
</Upload>
</div>
);
}
i've had similiar problem after updating version of antd. Here's the code how i fix this without sending request.
const handleChange = useCallback((info) => {
if (info.file.status === 'uploading') {
setImage({ loading: true, image: null });
info.file.status = 'done';
}
if (info.file.status === 'done') {
getBase64(info.file.originFileObj, (imageUrl) => {
const img = new Image();
img.src = imageUrl;
img.addEventListener('load', function () {
setImage({ loading: false, image: imageUrl });
setFileList([{ ...info.fileList[0] }]);
});
});
}
}, []);
inside condition (info.file.status === 'uploading')
i've changed info.file.status === 'done'
and surprsingly it work. Probably there's better solution to solve this, but maybe this will help
I have been banging my head against the wall for hours, and you won't believe what the fix to this is. Set fileList to undefined on the Upload component if the array is empty, which was mine and your default state value.
return (
<div className="App">
<Upload {...fileProps} fileList={fileList.length > 0 ? fileList : undefined}>
etc
</Upload>
</div>
);
As soon as I did that I was getting status "done" in my onChange handler.
I was tipped off by this comment in an AntD issue.
Edit: It appears that if you want to upload again after an initial batch, the fileList
prop has to stay undefined, which means even more work on our end...
In case it helps anyone, here is the working hook I made in our project to manage this. I wish it had half the React state tracking everything, but seems necessary in my case with this limitation of antd.
const useUpload = ({
fileBucket,
setFileList,
fileList,
}) => {
const [updatedFiles, setUpdatedFiles] = useState([]);
const [completed, setCompleted] = useState(0);
const [fileTotal, setFileTotal] = useState(0);
const storage = getStorage();
// Only update the file list when all files have their downloadUrl fetched
useEffect(() => {
if (fileTotal === 0) {
return;
}
if (fileTotal === completed) {
setFileList([...fileList, ...updatedFiles]);
setCompleted(0);
setFileTotal(0);
}
}, [completed, fileTotal, setFileList, updatedFiles, fileList]);
// antd cancels upload on a return of false
const beforeUpload = async (file) => {
// ... not relevant
};
const customRequest = ({ onError, onSuccess, file }) => {
const storageRef = ref(
storage,
`${fileBucket}/${new Date()} -- ${generateRandomId()}`
);
uploadBytes(storageRef, file)
.then((snapshot) => getDownloadURL(snapshot.ref))
.then((downloadUrl) => {
onSuccess({ downloadUrl });
})
.catch(() => {
onError();
});
};
const onChange = async ({ file, fileList }) => {
setFileTotal(fileList.length);
if (file.status === "done") {
const { downloadUrl } = file.response;
// Using the callback function on setState functions helps deal with race conditions.
// We still need to delay the update until all the files have loaded, hence the regretable two state values.
setUpdatedFiles((prevState) => {
const fileIndex = fileList.findIndex((fileInList) => {
return fileInList.uid === file.uid;
});
return [
...prevState,
{
...file,
url: downloadUrl,
pageNumber: fileIndex + 1,
},
];
});
setCompleted((prevState) => prevState + 1);
message.success(`${file.name} file uploaded successfully`);
}
if (file.status === "error") {
message.error(`${file.name} file upload failed.`);
}
};
return { beforeUpload, onChange, customRequest };
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With