This time I'm going to talk about the skills of developing upload components on the React-Flask framework. I currently mainly develop front-end with React, and in this process I have realized many interesting front-end UI frameworks - React-Bootstrap, Ant Design, Material UI, Bulma, etc. There are also many popular upload components, and currently the majority of users are jQuery-File-Upload and Dropzone, while the fast-growing newcomers include Uppy and filepond.
This time I'm going to talk about the skills of developing upload components on the React-Flask framework. I currently mainly develop front-end with React, and in this process I have realized many interesting front-end UI frameworks -React-Bootstrap、Ant Design、Material UI、Bulmawait. There are also many popular upload components, and currently the majority of users arejQuery-File-UploadandDropzone, and the fast-growing newcomers haveUppyandfilepond. What's more regretful isFine-UploaderThe author has decided not to maintain the reasons since 2018. As a latecomer, I won’t ask more about the reasons, but please respect the labor achievements of every open source author.
I'll choose hereReact-Dropzone, the reasons are as follows:
- Based on React development, high compatibility
- Highly recommended online, even Material UI uses it to develop and upload components
- Mainly
Drag
andDrop
Mainly, but the transmission logic can be designed by the developer. For example, try to use socket-io to transmit file chunks. The node full stack estimate is feasible, but I am using Flask here and I need to convert the Blob to the ArrayBuffer. But I didn't go on how to read and write it in Python.
Example Demonstration
1. Axios uploads normal files:
React-dropzone and import via 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 "./" 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 = ((bytes) / (k)); return parseFloat((bytes / (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(); (file => { ("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 attachments const removeFile = file => { const newFiles = [...files] ((file), 1) setFiles(newFiles) } useEffect(() => { // init uploader files setFiles([]) },[]) return ( <section className="container"> <div {...getRootProps({className: 'dropzone'})}> <input {...getInputProps()} /> <p>Drag the file or click to select the file😊</p> </div> <div className="demo-infinite-container"> <InfiniteScroll initialLoad={false} pageStart={0} loadMore={handleInfiniteOnLoad} hasMore={!loading && hasMore} useWindow= {false} > <List dataSource={files} renderItem={item=> ( < actions={[ // <a key="list-loadmore-edit">Edit</a>, <a key="list-loadmore-delete" onClick={removeFile}>delete</a> ]} // extra={ // } key={}> < avatar={ <> { !! && ['image/gif', 'image/jpeg', 'image/png'].includes() && <img width={100} alt='logo' src={} /> } </> } title={} description={formatBytes()} /> </> )} > {loading && hasMore && ( <div className="demo-loading-container"> <Spin /> </div> )} </List> </InfiniteScroll> </div> </section> ); }
Flask code:
def multiplefiles(): if 'files' not in : return jsonify({'message': 'No files! '}), 200 files = ('files') for file in files: if file: # Solve the Chinese problem of secure_filename through pinyin filename = secure_filename(''.join(lazy_pinyin()) Path(UPLOAD_FOLDER + '/' + file_info['dir_path']).mkdir(parents=True, exist_ok=True) ((UPLOAD_FOLDER + '/' + file_info['dir_path'], filename)) return jsonify({'message': 'Save successfully! ! '})
2. Import large files:
Generate chunks of files through the() method. Do not use non-sequential requests that may cause file corruption.
js code:
const promiseArray = (file => new Promise((resolve, reject) => { const chunkSize = CHUNK_SIZE; const chunks = ( / chunkSize); let chunk = 0; let chunkArray = new Array(); while (chunk <= chunks) { let offset = chunk * chunkSize; let slice = (offset, offset+chunkSize) ([slice, offset]) ++chunk; } const chunkUploadPromises = (slice, offset) => { const largeFileData = new FormData(); ('largeFileData', slice) return new Promise((resolve, reject) => { axios({ method: 'POST', url: '/api/files/largefile', data: largeFileData, headers: { "Content-Type": "multipart/form-data" } }) .then(resp => { (resp); resolve(resp); }) .catch(err => { reject(err); }) }) }; ( (previousPromise, [nextChunk, nextOffset]) => { return (() => { return chunkUploadPromises(nextChunk, nextOffset); }); }, ()); 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 = (UPLOAD_FOLDER + '/' + file_info['dir_path'], filename) try: with open(save_path, 'ab') as f: (offset) (()) print("time: "+ str(())+" offset: " + str(offset)) except OSError: return jsonify({'Could not write to file'}), 500
Conclusion
File transfer has always been a pain point in HTTP, especially large file transfer. The best way is to make a client yourself and transmit it through the FTP and FTPS protocols. The second method comes from a very centralized method of a large company. It uses the checksum of the file to determine whether the file has been uploaded to create the effect of instant transmission. The third method from decentralized Bittorrent is used to make file seeds for every user and provide file transfer assistance. It is not currently popular in China.
This is the end of this article about the development and uploading components based on React-Dropzone. For more related React-Dropzone component development content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!