This time I will talk about the skills of developing upload components on the React-Flask framework. I currently mainly develop front-ends with React. In the process, I got to know many interesting front-end UI frameworks - React-Bootstrap, Ant Design, Material UI, Bulma, etc. There are many popular upload components, and the ones with the most users are jQuery-File-Upload and Dropzone, while the fast-growing newcomers include Uppy and filepond. This time I will talk about the skills of developing upload components on the React-Flask framework. I currently mainly develop front-ends with React. In the process, I got to know many interesting front-end UI frameworks - React-Bootstrap, Ant Design, Material UI, Bulma, etc. There are many popular upload components, and the ones with the most users are jQuery-File-Upload and Dropzone, while the fast-growing newcomers include Uppy and filepond. It is a pity that the author of Fine-Uploader decided not to maintain it after 2018. As a latecomer, I will not ask about the reason, but please respect the work of every open source author. Here I choose React-Dropzone for the following reasons:
Example Demonstration1. Axios uploads ordinary files: Introduce react-dropzone through yarn: yarn add react-dropzone axios The front-end js is as follows (if there is any missing, please modify it yourself): import React, { useState, useCallback, useEffect, } from 'react'; import {useDropzone} from 'react-dropzone'; import "./dropzone.styles.css" import InfiniteScroll from 'react-infinite-scroller'; import { List, message, // Avatar, Spin, } from 'antd'; import axios from 'axios'; /** * Calculate file size * @param {*} bytes * @param {*} decimals * @returns */ function formatBytes(bytes, decimals = 2) { if (bytes === 0) return '0 Bytes'; const k = 1024; const dm = decimals < 0 ? 0 : decimals; const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; } /** * Dropzone upload file * @param {*} props * @returns */ function DropzoneUpload(props) { const [files, setFiles] = useState([]) const [loading, setLoading] = useState(false); const [hasMore, setHasMore] = useState(true); const onDrop = useCallback(acceptedFiles => { setLoading(true); const formData = new FormData(); smallFiles.forEach(file => { formData.append("files", file); }); axios({ method: 'POST', url: '/api/files/multiplefiles', data: formData, headers: { "Content-Type": "multipart/form-data", } }) then(resp => { addFiles(acceptedFiles); setLoading(false); }); }, [files]); // Dropzone setting const { getRootProps, getInputProps } = useDropzone({ multiple:true, onDrop, }); // Delete attachment const removeFile = file => { const newFiles = [...files] newFiles.splice(newFiles.indexOf(file), 1) setFiles(newFiles) } useEffect(() => { // init uploader files setFiles([]) },[]) return ( <section className="container"> <div {...getRootProps({className: 'dropzone'})}> <input { ...getInputProps()} /> <p>Drag files or click to select files😊</p> </div> <div className="demo-infinite-container"> <InfiniteScroll initialLoad={false} pageStart={0} loadMore={handleInfiniteOnLoad} hasMore={!loading && hasMore} useWindow= {false} > <List dataSource={files} renderItem={item=> ( <List.Item actions={[ // <a key="list-loadmore-edit">Edit</a>, <a key="list-loadmore-delete" onClick={removeFile}>Delete</a> ]} //extra={ // } key={item.path}> <List.Item.Meta avatar={ <> { !!item.type && ['image/gif', 'image/jpeg', 'image/png'].includes(item.type) && <img width={100} alt='logo' src={item.preview} /> } </> } title={item.path} description={formatBytes(item.size)} /> </List.Item> )} > {loading && hasMore && ( <div className="demo-loading-container"> <Spin /> </div> )} </List> </InfiniteScroll> </div> </section> ); } Flask code: def multiplefiles(): if 'files' not in request.files: return jsonify({'message': 'No file!'}), 200 files = request.files.getlist('files') for file in files: if file: # Solve the Chinese problem of secure_filename through pinyin filename = secure_filename(''.join(lazy_pinyin(file.filename)) Path(UPLOAD_FOLDER + '/' + file_info['dir_path']).mkdir(parents=True, exist_ok=True) file.save(os.path.join(UPLOAD_FOLDER + '/' + file_info['dir_path'], filename)) return jsonify({'message': 'Save successfully! !'}) 2. Large file import: Generate chunks of files through the file.slice() method. Do not use Promise.all as it may cause non-sequential requests and result in file corruption. js code: const promiseArray = largeFiles.map(file => new Promise((resolve, reject) => { const chunkSize = CHUNK_SIZE; const chunks = Math.ceil(file.size / chunkSize); let chunk = 0; let chunkArray = new Array(); while (chunk <= chunks) { let offset = chunk * chunkSize; let slice = file.slice(offset, offset+chunkSize) chunkArray.push([slice, offset]) ++chunk; } const chunkUploadPromises = (slice, offset) => { const largeFileData = new FormData(); largeFileData.append('largeFileData', slice) return new Promise((resolve, reject) => { axios({ method: 'POST', url: '/api/files/largefile', data: largeFileData, headers: { "Content-Type": "multipart/form-data" } }) .then(resp => { console.log(resp); resolve(resp); }) .catch(err => { reject(err); }) }) }; chunkArray.reduce( (previousPromise, [nextChunk, nextOffset]) => { return previousPromise.then(() => { return chunkUploadPromises(nextChunk, nextOffset); }); }, Promise.resolve()); resolve(); })) Flask code: filename = secure_filename(''.join(lazy_pinyin(filename))) Path(UPLOAD_FOLDER + '/' + file_info['dir_path']).mkdir(parents=True, exist_ok=True) save_path = os.path.join(UPLOAD_FOLDER + '/' + file_info['dir_path'], filename) try: with open(save_path, 'ab') as f: f.seek(offset) f.write(file.stream.read()) print("time: " + str(datetime.now()) + " offset: " + str(offset)) except OSError: return jsonify({'Could not write to file'}), 500 ConclusionFile transfer has always been a pain point for HTTP, especially large file transfer. The best way is to make a client yourself and transfer via FTP and FTPS protocols. The second method is a centralized one from a large company. It uses the checksum of a file to determine whether it has been uploaded, thus creating an instant upload effect. The third method from the decentralized Bittorrent is that each user acts as a file seed and provides assistance in file transfer. It is not widely used in China at present. This is the end of this article about developing upload components based on React-Dropzone. For more relevant React-Dropzone component development content, please search for previous articles on 123WORDPRESS.COM or continue to browse the following related articles. I hope everyone will support 123WORDPRESS.COM in the future! You may also be interested in:
|
>>: How to implement dual-machine master and backup with Nginx+Keepalived
In daily work, we sometimes run slow queries to r...
There are two installation methods for MySQL: msi...
Table of contents Preface 1. Install Docker 2. In...
I searched the entire web and found all kinds of ...
Set change mysqlroot password Enter the MySQL dat...
Preface Due to the weak typing of JS, loose writi...
I don’t know why, but UI likes to design honeycom...
Previously, we all used files with the suffix .ms...
In cells, light border colors can be defined indi...
In MySQL, databases correspond to directories wit...
Table of contents Introduction Download and insta...
Just as the title says. The question is very stran...
Open Source Database Architecture Design Principl...
Table of contents The role of cloneElement Usage ...
For example: Copy code The code is as follows: <...