DEV Community

Jakaria Masum
Jakaria Masum

Posted on

How to Upload Images to Cloudinary from the Client Side

Image description

Uploading images to Cloudinary from the client side can elevate your React applications by streamlining the process of storing and managing media. This blog provides a detailed, user-friendly guide to implementing this feature using React and TypeScript.

Prerequisites

Before getting started, ensure you have:

  • Basic familiarity with React and TypeScript.
  • A Cloudinary account. If you don’t have one, you can sign up here.

Why Use Cloudinary for Image Uploads?

Cloudinary is a powerful media management platform that:

  • Supports image and video storage.
  • Provides tools for transformations, optimizations, and delivery.
  • Offers a simple API for seamless integration.

By leveraging Cloudinary, you can save time and resources while providing a high-quality user experience.

Steps to Implement Image Upload to Cloudinary

1. Configure Cloudinary

  1. Log in to your Cloudinary account and navigate to the Dashboard.
  2. Copy your Cloud Name (you’ll need this for API calls).
  3. Go to Settings > Upload and create an unsigned upload preset. Note down the preset name for later use.

2. Set Up Your React Project

Begin by creating a new React application and installing Axios:

npm create vite@latest image-upload -- --template react
cd image-upload
npm install axios
Enter fullscreen mode Exit fullscreen mode

3. Create Utility File for Upload Logic

To handle uploads in a reusable way, create a utility function for Cloudinary interactions.

utils/uploadImage.ts
import axios from 'axios';

const CLOUD_NAME = "your-cloud-name"; // Replace with your Cloudinary cloud name
const UPLOAD_PRESET = "your-upload-preset"; // Replace with your upload preset

export const uploadImageToCloudinary = async (image: File): Promise<any> => {
  const formData = new FormData();
  formData.append('file', image);
  formData.append('upload_preset', UPLOAD_PRESET);

  const response = await axios.post(
    `https://api.cloudinary.com/v1_1/${CLOUD_NAME}/image/upload`,
    formData
  );
  return response.data;
};
Enter fullscreen mode Exit fullscreen mode

4. Create the Image Upload Component

Organize your project by creating a components directory. Inside it, add a new file named ImageUpload.tsx.

components/ImageUpload.tsx
import React, { useState } from "react";
import { uploadImageToCloudinary } from "../utils/uploadImage";

interface ImageUploadProps {
  setUrl: (url: string) => void;
}

const ImageUpload: React.FC<ImageUploadProps> = ({ setUrl }) => {
  const [image, setImage] = useState<File | null>(null);
  const [previewUrl, setPreviewUrl] = useState<string | null>(null);
  const [isUploading, setIsUploading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const handleImageChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0] || null;

    if (file) {
      // Validate file type and size (e.g., max 5MB)
      const validTypes = ["image/jpeg", "image/png", "image/gif"];
      if (!validTypes.includes(file.type)) {
        setError("Please upload a valid image (JPEG, PNG, GIF).");
        return;
      }
      if (file.size > 5 * 1024 * 1024) {
        setError("Image size must be less than 5MB.");
        return;
      }

      setImage(file);
      setPreviewUrl(URL.createObjectURL(file));
      setError(null);
    }
  };

  const handleUpload = async () => {
    if (!image) return;

    try {
      setIsUploading(true);
      const data = await uploadImageToCloudinary(image);
      setUrl(data.secure_url);
      alert("Image uploaded successfully!");
    } catch (error) {
      console.error("Error uploading image:", error);
      alert("Failed to upload the image. Please try again.");
    } finally {
      setIsUploading(false);
    }
  };

  return (
    <div style={styles.container}>
      <h1 style={styles.heading}>Upload Image to Cloudinary</h1>
      <input
        type="file"
        accept="image/*"
        onChange={handleImageChange}
        style={styles.fileInput}
      />
      {error && <p style={styles.errorText}>{error}</p>}
      {previewUrl && (
        <img src={previewUrl} alt="Preview" style={styles.previewImage} />
      )}
      <button
        onClick={handleUpload}
        disabled={isUploading}
        style={{
          ...styles.uploadButton,
          backgroundColor: isUploading ? "#ccc" : "#007BFF",
          cursor: isUploading ? "not-allowed" : "pointer",
        }}
      >
        {isUploading ? (
          <span>
            <span className="spinner" style={styles.spinner}></span>
            Uploading...
          </span>
        ) : (
          "Upload"
        )}
      </button>
    </div>
  );
};

const styles = {
  container: {
    maxWidth: "600px",
    margin: "auto",
    textAlign: "center" as const,
    fontFamily: "Arial, sans-serif",
    padding: "20px",
    border: "1px solid #ddd",
    borderRadius: "10px",
    boxShadow: "0 4px 8px rgba(0,0,0,0.1)",
  },
  heading: {
    marginBottom: "20px",
  },
  fileInput: {
    display: "block",
    margin: "20px auto",
  },
  previewImage: {
    width: "100%",
    height: "auto",
    marginBottom: "20px",
    borderRadius: "8px",
  },
  uploadButton: {
    padding: "10px 20px",
    color: "#fff",
    border: "none",
    borderRadius: "5px",
    fontSize: "16px",
  },
  errorText: {
    color: "red",
    fontSize: "14px",
    marginBottom: "10px",
  },
  spinner: {
    width: "16px",
    height: "16px",
    marginRight: "5px",
    border: "2px solid #fff",
    borderTop: "2px solid #007BFF",
    borderRadius: "50%",
    display: "inline-block",
    animation: "spin 1s linear infinite",
  },
};

export default ImageUpload;
Enter fullscreen mode Exit fullscreen mode

5. Integrate the Component

To include the ImageUpload component in your application, update App.tsx:

import { useState } from "react";
import ImageUpload from "./components/ImageUpload";

const App = () => {
  const [url, setUrl] = useState("");

  return (
    <div style={{ fontFamily: "Arial, sans-serif", padding: "20px" }}>
      <ImageUpload setUrl={setUrl} />
      {url && (
        <div style={{ marginTop: "20px", textAlign: "center" }}>
          <h2>Uploaded Image URL:</h2>
          <a href={url} target="_blank" rel="noopener noreferrer">
            {url}
          </a>
        </div>
      )}
    </div>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

6. Run Your Application

Start the development server with:

npm run dev
Enter fullscreen mode Exit fullscreen mode

Open http://localhost:5173 in your browser to test the image upload functionality. You can select an image, preview it, and upload it to Cloudinary.

This guide demonstrated how to build a feature-rich image upload component using React and TypeScript, integrated with Cloudinary. By keeping the image handling logic in the same file and abstracting the upload logic into a utility function, the code is easy to maintain and extend. Experiment with additional features like real-time transformations or backend integrations to unlock the full potential of Cloudinary!

Top comments (0)