Drag and Drop Image uploader using React, Dropzone and Cloudinary

In this article I will show you how to use React and dropzone to upload images in the server such as Cloudinary.

Advertisements

Let’s start by creating a new react app.

npx create-react-app image-app template --typescript

Then install react-dropzone

npm install react-dropzone
Advertisements

Inside the src folder create a new folder called ui. Then inside the ui folder create a new folder called image-uplaod. Inside the image-upload folder create a new file called ImageUpload.tsx

import React, { useMemo, useState, useEffect } from 'react';
import { useDropzone } from 'react-dropzone';

const baseStyle = {
  flex: 1,
  display: 'flex',
  flexDirection: 'column',
  alignItems: 'center',
  padding: '20px',
  borderWidth: 2,
  borderRadius: 2,
  borderColor: '#eeeeee',
  borderStyle: 'dashed',
  backgroundColor: '#fafafa',
  color: '#bdbdbd',
  outline: 'none',
  transition: 'border .24s ease-in-out'
};

const activeStyle = {
  borderColor: '#2196f3'
};

const acceptStyle = {
  borderColor: '#00e676'
};

const rejectStyle = {
  borderColor: '#ff1744'
};

const thumbsContainer: any = {
  display: 'flex',
  flexDirection: 'row',
  flexWrap: 'wrap',
  marginTop: 16
};

const thumb: any = {
  display: 'inline-flex',
  borderRadius: 2,
  border: '1px solid #eaeaea',
  marginBottom: 8,
  marginRight: 8,
  width: 100,
  height: 100,
  padding: 4,
  boxSizing: 'border-box'
};

const thumbInner = {
  display: 'flex',
  minWidth: 0,
  overflow: 'hidden'
};

const img = {
  display: 'block',
  width: 'auto',
  height: '100%'
};


interface IImageUpload {
files: File[],
onDrop: (acceptedFiles: File[]) => void
}

const ImageUpload: React.FC<IImageUpload> = ({ files, onDrop}) => {
  const {
    getRootProps,
    getInputProps,
    isDragActive,
    isDragAccept,
    isDragReject
  } = useDropzone({
    accept: 'image/*',
    onDrop: onDrop
  });

  const style: any = useMemo(() => ({
    ...baseStyle,
    ...(isDragActive ? activeStyle : {}),
    ...(isDragAccept ? acceptStyle : {}),
    ...(isDragReject ? rejectStyle : {})
  }), [
    isDragActive,
    isDragAccept,
    isDragReject
  ]);

  const thumbs = files.map((file: any) => (
    <div style={thumb} key={file.name}>
      <div style={thumbInner}>
        <img
          alt={file.name}
          src={file.preview}
          style={img}
        />
      </div>
    </div>
  ));

  useEffect(() => () => {
    // Make sure to revoke the data uris to avoid memory leaks
    files.forEach((file: any) => URL.revokeObjectURL(file.preview));
  }, [files]);

  return (
    <div className="container">
      <div {...getRootProps({ style })}>
        <input {...getInputProps()} />
        <p>Drag 'n' drop some files here, or click to select files</p>
      </div>
      <aside style={thumbsContainer}>
        {thumbs}
      </aside>
    </div>
  );
}

export default ImageUpload;
Advertisements

Login to cloudinary, you can signup for free if you don’t have an account. In the dashboard, take not of the API Base URL, you will need it to upload your image.

Note: Don’t show to anyone your API secrets. I will replace mine later after this tutorial, that’s why it’s fine to show it here.

Click the settings button then go to Upload tab.

In the Upload tab scroll down until Upload presets. Click the Enable unsigned uploading.

Then a new upload preset will be created with a mode of Unsigned. You will need this value later in uploading the images in your cloudinary account.

Click Save

Advertisements

Now back in our code. We will use axios to upload our image. Run this command to install axios.

npm install axios

Then update App.tsx

import React, { useState } from 'react';
import './App.css';
import ImageUpload from './ui/imge-upload/ImageUpload';
import axios from 'axios';

const App = () => {
  const [files, setFiles] = useState<File[]>([]);

  const onDrop = (acceptedFiles: File[]) => {
    setFiles(acceptedFiles.map(file => Object.assign(file, {
      preview: URL.createObjectURL(file)
    })));
  }

  const upload = () => {
    const uploadURL = 'https://api.cloudinary.com/v1_1/lexcalin/image/upload';
    const uploadPreset = 'ibejdqmo';

    files.forEach(file => {
      const formData = new FormData();
      formData.append('file', file);
      formData.append('upload_preset', uploadPreset);
      axios({
        url: uploadURL,
        method: "POST",
        headers: {
          "Content-Type": "application/x-www-form-urlencoded"
        },
        data: formData
      })
      .then(res => console.log(res))
      .catch(err => console.log(err))
    })
  }

  return (
    <div className="App">
      <ImageUpload files={files} onDrop={onDrop}/>
      <button onClick={() => upload()}>Upload</button>
    </div>
  );
}

export default App;

In the upload function, replace the uploadUrl value with your cloudinary API base url /image/upload then replace the uploadPreset with the generated upload preset in earlier step.

Run the application using the command

npm start

Now you should be able to drag and drop images in your application and upload it to cloudinary

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s