I am trying to create a Next JS video file uploader using Axios and NextApiRequests.
I want to implement a button to cancel an ongoing file upload once the handleUpload function is triggered but have no luck doing so.
The issue is that the file keeps uploading after the axios signal is aborted. As video files are pretty large it is far from optimal.
The setup is the following one :
upload.tsx
const inputRef = useRef(null);
const uploadController = new AbortController();
const [selectedFile, setSelectedFile] = useState(null);
const [progress, setProgress] = useState(0);
const [uploadStatus, setUploadStatus] = useState("select");
const clearFileInput = () => {
if (uploadStatus == "uploading") {
uploadController.abort();
}
inputRef.current.value = "";
setSelectedFile(null);
setProgress(0);
setUploadStatus("select");
};
const onChooseFile = () => {
inputRef.current.click();
}
const handleUpload = async (event: any) => {
if (event.target.files && event.target.files.length > 0) {
setSelectedFile(event.target.files[0]);
try {
setUploadStatus("uploading")
const formData = new FormData();
formData.append("myImage", event.target.files[0]);
const { data } = await axios.post('/api/upload', formData,
{
onUploadProgress: ProgressEvent => {
const uploadProgress: number = parseFloat((ProgressEvent.loaded / (ProgressEvent.total || 1) * 100).toFixed(2))
setProgress((progress) => uploadProgress)
},
signal: uploadController.signal
}
)
setUploadStatus("done")
} catch (error) {
console.log(error)
}
}
};
/api/upload.ts
import type { NextApiRequest, NextApiResponse } from 'next'
import formidable from 'formidable';
import path from 'path';
import fs from "fs/promises";
export const config = {
api: {
bodyParser: false,
},
};
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const options: formidable.Options = {}
const uploadDir = path.join(process.cwd(), "/public/Assets/PendingUploads")
options.uploadDir = uploadDir;
options.filename = (name, ext, path, form) => {
return Date.now().toString() + "_" + path.originalFilename;
};
options.maxFileSize = Infinity;
const form = formidable(options)
new Promise((resolve, reject) => {
form.parse(req, (err, fields, file) => {
if (err) reject(err)
resolve({ fields, file })
})
form.on("file", (field, file) => {
try {
const uploadPath = path.join(uploadDir, path.basename(file.filepath).split(".").join(""))
fs.mkdir(uploadPath)
fs.rename(file.filepath, path.join(uploadPath, path.basename(file.filepath)))
} catch (error) {
console.log(error)
}
})
})
return res.status(200).json("OK")
}
export default handler;
I have tried :
- Axios cancellation with signal/canceltoken but the api doesn’t get the cancellation
- Event listeners and req.on statements with no luck
- A few other things I did not keep track of…
Thank you for your help and time !