It’s one thing to create a beautiful drag and drop feature that allows you to select multiple images at once and quite another to upload multiple files to Cloudinary. Well, who says you can’t do both?
This is the second of a two-part series. In this article, I will show you how to upload multiple files to Cloudinary using a drag and drop API. In addition to that, we will render the uploaded images in a separate view. The application will have an index view displaying the drag and drop form, allowing you to select multiple images at once. When the submit button is clicked, the files will be uploaded, and on completion, the application will render the uploaded images in a grid. React Router will be used to handle the transition between views.
We will take advantage of Cloudinary’s comprehensive API and easy-to-use SDKs to manage our media resources. You will need a Cloudinary account for this tutorial. Create one here if you don’t already have one.
For UI components in our application, we will use antd, while axios will be used for uploading our images to our Cloudinary store and rendering the resulting images.
Here is a link to the demo on CodeSandbox.
If you followed the first part of this series, you can skip this step and move on to the next step. Clone this repository and install the packages using the following commands:
git clone https://github.com/ifeoma-imoh/drag-and-drop-demo cd drag-and-drop-demo npm installCode language: PHP (php)
Once this is done, we can install the dependencies we’ll need for our application.
npm i axios react-router-dom@6 cloudinary-reactCode language: CSS (css)
Next, we need to create some environment variables to hold our Cloudinary details. We will be sending images to Cloudinary via unsigned POST requests for this tutorial. To do this, we need our account cloud name and an unsigned upload preset. Create a new file called
.env at the root of the project and add the following to it:
This will be used as a default when the project is set up on another system. To update your local environment, create a copy of the
.env file using this command:
cp .env .env.localCode language: CSS (css)
By default, this local file is added to
.gitignore and mitigates the security risk of inadvertently exposing secret credentials to the public. You can update .env.local with your Cloudinary cloud name and generated upload preset.
Create a new folder named
utility in your
src directory. This folder will hold all the helper classes we need in our components. In the
utility folder, create a file called
cloudinaryConfig.js. This file will give access to the environment variables and prevent repeated
process.env. calls throughout the project. Add the following to your
We need to make two requests for this application – one to upload a new image to Cloudinary and the other to download the image from a URL our application will build. In the
utility folder, create a new file named
api.js and add the following to it:
uploadImage function is used to upload the provided file to Cloudinary. It makes a POST request to Cloudinary, providing the file and our earlier defined upload preset. If the request is handled successfully, the provided callback is executed, passing the Cloudinary response as a function parameter.
Let’s implement the function to upload files to Cloudinary. At the moment, we have a hook that provides the functionality needed for file selection. We can add another function to submit the files and add it to the returned array. Open the
src/hooks/useFileSelection.js file and update its content as shown below:
We’ve made a few additions. First, we added a boolean state variable to indicate when the images are being uploaded, and we can use this to modify the UI to keep the user informed.
Next, we added a function named
uploadSelection. When more than one image is selected, the function iterates through each image and makes a POST request to the Cloudinary store using the
uploadImage function we declared earlier. If the upload is successful, we append the response data to an array named
uploadResults. By comparing the lengths of the
uploadResults array, we can determine when the upload is complete and redirect to the
/results route (which we will configure later). To keep things simple, we pass the results via the navigate function, which we retrieved from React router’s
Finally, we updated the returned array to include the
uploadSelection function and the
At the moment, our
src/App.js file contains the JSX and functionality for selecting/uploading images. Before we add anything else, let’s move everything to a new component to keep things lean and simple. In the
src/components directory, create a new file named
ImageUpload.js and add the following to it:
In addition to moving the JSX and functionality to a new component, we’ve also integrated the upload functionality by including
uploadSelection in our destructuring of the
We’ve also added an
onClick handler to the submit button, which calls the
uploadSelection function. While the upload is in progress, the button state is set to loading via the loading prop.
Next, we need a component to render a single image in the results route. In the
src/components directory, create a new file called
Image.js and add the following to it:
This component takes the public id of the image, the original filename, and the Date Time at which it was uploaded as props and renders the image using the Cloudinary-react SDK. It performs one transformation on the image – scaling it to a height of 240px and width of 300px. The image is wrapped in a Card containing the original filename as its title and the upload Date Time as the description.
Next, let’s add a component that will be rendered for the results route. This component will take the uploaded results passed and render each result using the
Image component we declared earlier. In the
src/components directory, create a new file called
ImageGrid.js and add the following to it:
In this component, we make a
useEffect call which runs once when the component is mounted. This call retrieves the uploaded results passed to the component via the
location state (provided by react-router-dom) and updates the
resources state variable accordingly.
Next, we declare a function named
returnToUploads which takes the user back to the index page (where we upload images).
Finally, we return the JSX for this component. Before iterating through the results and rendering the associated images, we add a PageHeader component, which is used to return to the image uploads view.
Now that we have all our components in place, let’s implement the routing functionality to navigate between components. In the
src/utility folder, create a new file called
routes.js and add the following to it:
Here we define Route Objects used by the
useRoutes hook to render the
Next, update your
src/App.js file to match the following :
Using the earlier declared routes object and the
useRoutes hook, we render a
Finally, wrap the
<App> component in a
BrowserRouter. To do this, update
src/index.js to match the following:
With this in place, our application is complete! Run this command to spin up a local development server:
The application will be available at http://localhost:3000/.
Find the complete project here on GitHub.
In this article, we looked at how to upload multiple files to Cloudinary. By combining this with a drag and drop API, which allows users to upload multiple files at once, we can provide a seamless experience for the user – no more uploading files one at a time!
Here are some resources you may find helpful: