基于react-dropzone实现文件上传进度(百分比/MB传输量)技术问询
Got it, let's tackle adding upload progress tracking (either percentage or transferred MB) to your react-dropzone setup. The core issue here is that the standard fetch API doesn't natively expose upload progress events, so we'll use XMLHttpRequest instead—it's straightforward and gives us direct access to progress updates. Here's how to adjust your existing code step by step:
Step 1: Add Progress Tracking State to Your Component
First, initialize state variables to keep track of upload progress and upload status:
constructor(props) { super(props); this.state = { filesToBeSent: [], filesPreview: [], showNotification: false, uploadResponse: null, fileType: false, fileSize: false, uploadProgress: 0, // Tracks upload percentage isUploading: false, transferredMB: 0 // Tracks data transferred in MB }; }
Step 2: Create a Progress-Enabled Upload Function
Replace or wrap your existing uploadApi with a function that uses XMLHttpRequest to listen for upload progress events:
uploadWithProgress(formData, onProgress) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); // Replace with your actual upload API endpoint xhr.open('POST', 'YOUR_UPLOAD_ENDPOINT_URL'); // Listen for upload progress updates xhr.upload.addEventListener('progress', (event) => { if (event.lengthComputable) { const progressPercent = Math.round((event.loaded / event.total) * 100); const transferredMB = (event.loaded / (1024 * 1024)).toFixed(2); onProgress(progressPercent, transferredMB); } }); // Handle successful upload xhr.onload = () => { if (xhr.status >= 200 && xhr.status < 300) { resolve(JSON.parse(xhr.responseText)); } else { reject(new Error(`Upload failed with status ${xhr.status}`)); } }; // Handle network errors xhr.onerror = () => reject(new Error('Network error during upload')); xhr.send(formData); }); }
Step 3: Update the onDrop Method to Track Progress
Modify your onDrop function to start tracking progress when an upload begins, and update the state with real-time progress data:
onDrop(acceptedFiles) { const { filesToBeSent } = this.state; if (acceptedFiles.length) { const file = acceptedFiles[0]; if (file.type === FileTypeList.TYPE) { // Reset progress state before starting upload this.setState({ isUploading: true, uploadProgress: 0, transferredMB: 0, fileType: false, fileSize: false }); const updatedFiles = [...filesToBeSent, file]; const formData = new FormData(); formData.append("file", file); // Use our progress-enabled upload function this.uploadWithProgress(formData, (progressPercent, transferredMB) => { this.setState({ uploadProgress: progressPercent, transferredMB }); }) .then((response) => { this.setState({ filesPreview: [], filesToBeSent: [{}], showNotification: true, uploadResponse: response, isUploading: false }); this.props.fetchHistory(); }) .catch((error) => { console.error('Upload failed:', error); this.setState({ isUploading: false }); // Add custom error handling here (e.g., show an error notification) }); } else { this.setState({ fileType: true, isUploading: false }); } } else { this.setState({ fileSize: true, isUploading: false }); } }
Step 4: Display Progress in Your JSX
Update your Dropzone component to show the upload progress while the file is being uploaded:
<Dropzone maxSize={this.props.maxSize} onDrop={(files) => this.onDrop(files)}> {({ getRootProps, getInputProps }) => { return ( <div {...getRootProps()} className={"dropzone"}> <UploadPanel id="uploadFileContainerId"> {this.state.isUploading ? ( <div className="upload-progress-container"> <p>Upload Progress: {this.state.uploadProgress}%</p> <p>Transferred: {this.state.transferredMB} MB</p> {/* Basic progress bar - add CSS to style this */} <div className="progress-bar"> <div className="progress-fill" style={{ width: `${this.state.uploadProgress}%` }} /> </div> </div> ) : ( <> <p> <img id="uploadImage" src={UploadImage} /> </p> <input {...getInputProps()} /> <div>{t("assets:UPLOAD_FILE")}</div> <Note> {this.props.maxSizeTitle ? t("workers:UPLOAD_WORKER_FILE_SIZE") : t("assets:UPLOAD_FILE_SIZE")} </Note> </> )} </UploadPanel> </div> ); }} </Dropzone>
Quick Notes:
- Don't forget to replace
YOUR_UPLOAD_ENDPOINT_URLin theuploadWithProgressfunction with your actual API endpoint. - The
progress-barandprogress-fillclasses are placeholders—add custom CSS to style them (e.g., a gray container with a colored fill that expands as progress increases). - If your existing
uploadApiis a separate service, you can modify it to accept anonProgresscallback instead of creating a new function, to keep your codebase consistent.
内容的提问来源于stack exchange,提问作者Arun Arya

