Uploading Thumbnail Images to the API in React
This is gonna be a really fun guide because in this lesson we're gonna walk through and actually finish the image upload component.
Guide Tasks
  • Read Tutorial
  • Watch Guide Video
Video locked
This video is viewable to users with a Bottega Bootcamp license

Which means we're gonna be able to take all of the work we've done with setting up dropzone, and once the image is added to the dropzone component here we're gonna be able to push it up through the API to the server and then have it render here on the screen.

That's actually the reason I picked out to work with the thumbnail image first because that is what's used on the homepage and the sidebar list. So with saying all of that let's actually dive into the code.

So I'm going to come here and we're simply gonna have to add a few methods and a few processes. So we're not that far away, and hopefully, this guide will not take as long as the last one. So the very first thing we're gonna do is we need to build out a method for handling the process for when an image is dropped onto that dropzone component.

So I'm gonna create a handler method here, and this is gonna be specific to the thumbnail. So here we can say handleThumbDrop, it's not gonna take any arguments and inside of it we're gonna return an object. So this handling of drop processes, this is something that is also specified in the documentation for how dropzone works.

So you can name the method anything that you want. Just like we could have named the componentConfig anything we wanted and the djsConfig anything we wanted, but we do have to return a specific set of items. So in this case what we're going to return is an addedfile value.

So here what I can do is say return addedfile, and that's actually all lowercase. So addedfile, and this expects a function. So the first argument is the file and this is gonna look a little bit weird if you've never worked with this before, but don't worry, we're gonna go back and review each line and talk about what it's doing.

So this file is going to call a function, or I should say this file's gonna be called inside of a function. And so we're gonna use an arrow function and then say this.setState and then inside of here what I wanna do is setState and say thumb_image and then pass in exactly what that value is, which is the file.

portfolio-form.js

handleThumbDrop() {
  return {
    addedfile: file => this.setState({ thumb_image: file })
  };
}

Okay, so what's going on right here? So we have this drop process which we are going to pass to the dropzone component, and whenever something, specifically a file, is dropped on the component then it is going to check and it's gonna look inside of this return statement and it's gonna see what files or what methods do I have access to.

It's gonna find this addedfile function here, and then it is gonna run it. It's gonna pass in the file that was dropped in, and then it's going to say, okay, I want to setState with that file. Okay, so now that we have that let's also add it up here, so we're gonna bind it to this. So I'll say this.handleThumbDrop = this.handleThumbDrop.bind to this.

this.handleThumbDrop = this.handleThumbDrop.bind(this);

And now we have to call it from down inside of the dropzone component itself. So here I'm going to call it, and what actually has to be called in here is not handleThumbDrop because the dropzone component wouldn't know about that prop. But it does know about a prop called eventHandlers, spelled out exactly like this with a capital H, equals, and then I can call this.handleThumbDrop and make sure you call it with the parens just like that, and so now we can hit save.

eventHandlers={this.handleThumbDrop()}

And with all of this in place the last thing that we have to do now is update our buildForm method. 'Cause remember that our buildForm is what actually connects our state with what gets submitted in the API. Now we can't just copy and paste this and say form append portfolio_item, and then, in this case, thumb_image with this.state and then thumb_image.

The only way you could do that is if you always knew you were gonna get a thumb image. But because of the way the images work, images have to be treated differently than text. If you upload an empty string for name or description the server's gonna be perfectly fine with that, it's simply going to put in a null value inside the database.

However, if you try to do that with an image what's going to happen is the server's going to expect an image. If we pass up a portfolio item thumb_image key it's going to expect the value to actually be a file, and it's gonna start several processes on its side, it's gonna bring its own special encoder, it's gonna do things like that, and when it finds nothing there it's gonna throw an error.

So we do not want that, we only want to append this formData item if this exists. So we're gonna add a conditional here, so I'll say if and then we can just say this.state.thumb_image, and so we can say I only want to append this thumb_image value to the formData if we actually have it, so if an image file has been uploaded.

portfolio-form.js

if (this.state.thumb_image) {
  formData.append("portfolio_item[thumb_image]", this.state.thumb_image);
}

So with all of this, I believe we have everything we need. So this is pretty cool, let's hit refresh and see if it works. I'm gonna add something here, I'll say with an image, and we don't have to add any other values in. You can come out, pick out any image that you have on your system, as long as it's a jpeg or a png, and now if I click save it looks like it works.

Yes, so this got wrapped up in the formData object. It went to the server, it all got added, and it even got added to the list. You can also confirm this if you hit refresh on DevCamp space if you have it open and scroll all the way down.

You can see we have this new record called with an image and it does have a thumbnail image there, so that is working really nicely. You may notice that we're not clearing out the image or the form or anything like that yet, we'll take care of that later.

But for right now this is all working perfectly. So in the next few guides we're gonna start building out the same functionality but for the other two images, for the logo and also for the banner image.

Resources