Image Uploads in a React/Go stack

James Howard
3 min readMar 28, 2024

I’ve recently been having a lot of fun learning a new-to-me development stack after a few years in a hands-off management role and it’s great to be finally getting a little bit productive in it. So my latest task was to figure out how to implement image uploads in this new stack.

The general approach I decided to take was to start work on the front-end UI, move on to API implementation and then marry the two together once each individual part was working correctly. If I even deploy what I’m working on, I will eventually need to add object storage and a CDN but this is fine for now. I’ll also keep things a little simpler by assuming the images can be public as this avoids the hassle of injecting a bearer token into the image src requests.

Choosing a Front-End Library

While it isn’t a huge chunk of work to implement the interface from scratch, I figured it was worth a quick look to see if there was a package that could give me a bit of a head start. I looked at a few and in the end I chose to use the react-images-uploading package as it did most of what I needed to do. This took care of rendering the image, some drag and drop and buttons to allow images to be removed. It also allowed for multiple images to be uploaded at the same time but since I didn’t want that, I’d have to stub this stuff out.

Initial Changes

The first set of changes was to allow me to create a single image version of the component. I added an isMultiple variable to the containing component and then made the individual image buttons conditional on this being true.

The next step was to add in a save button that I would later connect up to my API request to enable the image upload. Then, since I’m using bootstrap, I applied a few bootstrap styles to things to make it all look reasonably presentable.

The final thing was to add in a default image that would be displayed if the image list was empty so that the user can see which image they are replacing.

<ReactImageUploading
value={images}
multiple={isMultiple}
onChange={onChange}
maxNumber={maxNumber}
dataURLKey="data_url"
>
{({
imageList,
onImageUpload,
onImageRemoveAll,
onImageUpdate,
onImageRemove,
isDragging,
dragProps,
}) => (
// write your building UI
<div className="upload__image-wrapper">
<button onClick={onImageRemoveAll}>Remove all images</button>
{
imageList.map((image, index) => (
<div key={index} className="image-item">
<img src={image['data_url']} alt="" width="100%"
/>
{getMultipleImageButtons(onImageUpdate, index, onImageRemove)}
</div>
))
}
{getDefaultImage()}
<div className="p-2">
<button
className="btn btn-secondary mr-1"
style={isDragging ? {color: 'red'} : undefined}
onClick={onImageUpload}
{...dragProps}
>
Click or Drop here
</button>
<button disabled={imageList.length == 0}
className="btn btn-primary ml-1"
onClick={() => saveImages()}>
Save
</button>
</div>
</div>
)}
</ReactImageUploading>
function getMultipleImageButtons(onImageUpdate: (index: number) 
=> void, index: number, onImageRemove: (index: number) => void) {
if (isMultiple) {
return (<div className="image-item__btn-wrapper">
<button onClick={() => onImageUpdate(index)}>Update</button>
<button onClick={() => onImageRemove(index)}>Remove</button>
</div>)
} else {
return ("")
}
}
function getDefaultImage() {
if ((images.length == 0) && (imageSource != null)) {
console.log("Get Default: " + imageSource)
return (
<div key="0" className="image-item">
<img src={imageSource} alt="" width="100%"/>
</div>
)
}
}

Conclusion

This code is obviously incomplete as there is no way to actually submit the saved image but I will revisit this in a later article once I’ve got the back-end working cleanly. I will also need to do some further work for error handling. But right now, I’ve got enough front-end and it’s time to move on to the API which I’ll document in my next article.

--

--