question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Document support for using with react-dropzone

See original GitHub issue

I’ve personally integrated this with react-dropzone, but the code was too specific to my use case to release.

We should add some code and documentation for the preferred way to integrate with react-dropzone.

For those wondering, I essentially bypassed the ReactS3Uploader react component and just included s3upload.js directly. Using the S3Upload class, I just wrapped each dropped file in a new instance, which kicks off the same upload process as using the component.

Issue Analytics

  • State:open
  • Created 8 years ago
  • Comments:10 (4 by maintainers)

github_iconTop GitHub Comments

14reactions
seanadkinsoncommented, Feb 9, 2016

So I basically wrapped the s3uploader in a class that fires events and returns a promise.

Here is the class I called S3FileUploader:

import Promise from 'bluebird';
import _ from 'lodash';
import klass from 'klass';
import Events from 'events';
import S3Upload from 'react-s3-uploader/s3upload.js';

const EventEmitter = Events.EventEmitter;


const S3FileUploader = klass({

    initialize(file, options) {
        this.file = file;
        this.preview = file.preview || URL.createObjectURL(file);
        this.emitter = new EventEmitter();
        this.opts = _.defaults(options || {}, {
            signingUrl: '/s3/signUpload'
        });
    },

    getFile() {
        return this.file;
    },

    getFileType() {
        return this.getFile().type;
    },

    getPreview() {
        return this.preview;
    },

    getFilename() {
        return this.getFile().name;
    },

    isImage() {
        return /^image\//.exec(this.getFileType());
    },

    getResultS3Filename() {
        return this.result && this.result.filename;
    },

    getPublicUrl() {
        return this.result && this.result.publicUrl;
    },

    on(event, callback) {
        this.emitter.addListener(event, callback);
    },

    off(event, callback) {
        this.emitter.removeListener(event, callback);
    },

    cancel() {
        if (this.upload) {
            this.upload.abortUpload();
            this.emitter.emit('abort');
            this.upload = null;
        }
    },

    markFailed() {
        this.failed = true;
    },

    isFailed() {
        return !!this.failed;
    },

    getContentDisposition() {
        let isPdf = this.getFileType() == 'application/pdf';
        return isPdf ? 'inline' : 'auto';
    },

    start() {
        return new Promise((resolve, reject) => {
            this.upload = new S3Upload({
                files: [this.file],
                signingUrl: this.opts.signingUrl,
                signingUrlQueryParams: this.opts.signingUrlQueryParams,
                contentDisposition: this.getContentDisposition(),
                onProgress: (percent, status) => {
                    this.emitter.emit('progress', percent, status);
                },
                onFinishS3Put: (result) => {
                    this.result = result;
                    this.emitter.emit('complete', result);
                    resolve(result);
                },
                onError: (status) => {
                    this.emitter.emit('error', status);
                    this.markFailed();
                    reject(status);
                }
            });
            this.emitter.once('abort', resolve);
        });
    }

});

export default S3FileUploader;

And then I’m using this in the onDrop function called from react-dropzone:

        onDrop(files) {
            let existingUploaders = this.state.uploaders;
            let existingUploadersByName = _.indexBy(existingUploaders, uploader => uploader.getFilename());

            let uploaders = _.map(files, (file) => {
                let filename = file.name;
                if (existingUploadersByName[filename] || !this.acceptsType(file.type)) {
                    return null;
                }

                let uploader = new S3FileUploader(file);

                uploader.on('progress', (percent) => {
                    this.setState({
                        [`progress-${filename}`]: {
                            percent: percent,
                            message: m('common.attachments.uploading')
                        }
                    });
                });

                uploader.on('complete', () => {
                    this.setState({
                        [`progress-${filename}`]: {
                            isComplete: true,
                            message: m('common.attachments.complete')
                        }
                    });
                });

                uploader.on('error', (status) => {
                    this.setState({
                        hasFailedUpload: true,
                        [`progress-${filename}`]: {
                            hidePercent: true,
                            message: status || m('common.attachments.error')
                        }
                    });
                });

                return uploader;
            });

            uploaders = _.compact(uploaders);

            if (!this.props.allowMultiple && uploaders.length) {
                _.each(existingUploaders, up => this.removeUpload(up));
                existingUploaders = [];
            }

            this.setState({
                uploaders: existingUploaders.concat(uploaders),
                uploading: true
            });

            return Promise.resolve()
                .then(() => {
                    return Promise.each(uploaders, uploader => uploader.start());
                })
                .finally(() => {
                    this.setState({ uploading: false });
                });
        },
1reaction
ttyaocommented, Feb 9, 2016

I am essentially looking for doing the same thing! @seanadkinson do you mind share your solution (after remove all personal credentials of course)?

Read more comments on GitHub >

github_iconTop Results From Across the Web

react-dropzone
Simple React hook to create a HTML5-compliant drag'n'drop zone for files. Documentation and examples at https://react-dropzone.js.org.
Read more >
React Dropzone - GitHub
React Dropzone integrates perfectly with Pintura Image Editor, creating a modern image editing experience. Pintura supports crop aspect ratios, resizing, ...
Read more >
Accepting specific file types - react-dropzone
By providing accept prop you can make the dropzone accept specific file types and reject the others. The value must be an object...
Read more >
Create a Drag-and-Drop Zone in React ... - OpenReplay Blog
It's a simple React hook to create an HTML-5 compliant drag-and-drop zone for files. Dropzone provides additional functions such as customizing ...
Read more >
React Dropzone and File Uploads in React - Upmostly
React Dropzone and file uploads in React banner showing a cloud file upload image next to. In this tutorial, we'll learn how to...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found