SoFunction
Updated on 2025-04-07

Develop upload component functions based on React-Dropzone (instance demonstration)

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-BootstrapAnt DesignMaterial UIBulmawait. 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:

  1. Based on React development, high compatibility
  2. Highly recommended online, even Material UI uses it to develop and upload components
  3. Mainly Drag andDropMainly, 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>,                                &lt;a key="list-loadmore-delete" onClick={removeFile}&gt;delete&lt;/a&gt;
                            ]}
                            // extra={
                                
                            // }
                            key={}&gt;
                            &lt; 
                                avatar={
                                    &lt;&gt;
                                    {
                                        !! &amp;&amp; ['image/gif', 'image/jpeg', 'image/png'].includes() &amp;&amp;
                                        &lt;img 
                                            width={100}
                                            alt='logo'
                                            src={}
                                        /&gt;
                                    }
                                    &lt;/&gt;
                                }
                                title={}
                                description={formatBytes()}
                            /&gt;
                        &lt;/&gt;
                    )}
                &gt;
                    {loading &amp;&amp; hasMore &amp;&amp; (
                        &lt;div className="demo-loading-container"&gt;
                            &lt;Spin /&gt;
                        &lt;/div&gt;
                    )}
                &lt;/List&gt;
            &lt;/InfiniteScroll&gt;
        &lt;/div&gt;
        &lt;/section&gt;
    );
}

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!