Search code examples
reactjssuperagent

react js / superagent / file dropzone


I have a comments widget, in React js (jsx), and I'm using React Dropzone and uploading the dropped files to the server, using superagent.

I need to get the file object (containing my app's file id,etc) returned from my app, and associate them with the comment that the user will submit. I am attempting to assign the file objects to a state variable, 'attachments'. Because of the async nature of superagent, I think, I am actually populating my state variable with an empty array.

I have tried to use a callback, but got an 'undefined' error.

Here is the code:

onDrop: function (newFiles) {


    newFiles.forEach((file)=>
    {
        this.setState({files: this.state.files.concat(file)});
    })

    var attachments = [];

    var req = request.post('/attachments/create');
    req.set('Accept', 'application/json');
    newFiles.forEach((file)=> {
        req.attach('img_attach', file);
        req.field('filename', file.name);
        req.field('itemType', 'comment');
        req.field('itemId', false);
        req.end(function(err,res){
            var json = $.parseJSON(res.text);
            attachments.push(json);
            attIds.push(json.id);

        });

    });

    attachments.forEach((file)=>
    {
        this.setState({
            attachments:this.state.attachments.concat([file])});
    });

},

Here is the callback attempt which returns "Cannot read property 'setState' of undefined":

function fileAttach(err,res)
    {
        var json = $.parseJSON(res.text);
        this.setState({attachments:this.state.attachments.concat([json])});

    }

For the callback, instead of this

req.end(function(err,res){
            var json = $.parseJSON(res.text);
            attachments.push(json);
            attIds.push(json.id);

        });

I use this

req.end(fileAttach);

So, one possibility is that I'm looking for a 'context' option, similar to jquery, that allows me to use 'this' in the callback.


Solution

  • So, you were on the right track for the first issue I see. You need to bind the context to that function. It's already been answered by LodeRunner28 in the comments, but you'd do:

    req.end(fileAttach.bind(this))

    If you're not familiar, Function.prototype.bind allows you to manually force a context variable for any function. It's incredibly handy, and it means you never have to rely on the library (eg. jQuery) to provide a context arg, you can just specify it yourself :)

    The bigger issue I see is the way you're using SuperAgent. I believe you're actually sending a whole bunch of requests; calling .end triggers SuperAgent to make the request, and you're doing it inside the forEach loop.

    I'm not super familiar with SuperAgent, but I believe you can just do:

    newFiles.forEach( file => {
      req.attach('img_attach', file);
      req.field('filename', file.name);
      req.field('itemType', 'comment');
      req.field('itemId', false);
    });
    
    req.end(fileAttach.bind(this));