DEV Community

Cover image for Uploading media assets from React using Cloudinary
Tulsi Prasad
Tulsi Prasad

Posted on • Originally published at wirescript.now.sh

Uploading media assets from React using Cloudinary

Hey everyone! In today's standards, it's not uncommon to see every other website has some kind of visual content by themselves or for the user to upload. And keeping factors such as performance, rich image optimization it becomes even difficult to handle all of it using built in techniques. That's the problem Cloudinary solves almost perfectly, thus we'll see how to implement it in our React app ecosystem.

Living Example

I usually don't like making examples just for blogs (as they're time consuming) but I like showing real projects that I worked on and how I implemented it in my project.

Speaking of, last week I made this app to learn about authentication, where you can create your account (OAuth/Local) and edit your info, like image and name, so I liked to try out Cloudinary. You can tap Change Photo (on edit page) to add your photos, this is handled by Cloudinary in React itself. You can find it on my GitHub. (talkto-frontend and talkto-backend)

Home page of Talk to

Edit page of Talk to

Do you have a Cloudinary Account?

You can create a free account on Cloudinary, here. I'll show how to setup your project on there with screenshots below.

Creating the Markup

So to upload any file from the frontend, we need to have an input tag with type equals to file. Then we'll pass the file inside a FormData object and make the post request to our Cloudinary endpoint (we'll see how to get one below).

Here, InputFieldImage is a child (presentational) component which contains our input tags and all the values are passed to it from its stateful parent component. Link to source.

const InputFieldImage = ({ title, id, value, ...rest }) => (
  <FieldContainer>
    <ImageFieldContainer>
      <img className="upload-image" src={value} alt="Person Profile" />
      <span className="material-icons input-icon">camera_alt</span>
      <input id={id} {...rest} />
      <label htmlFor={id}>{title}</label>
    </ImageFieldContainer>
  </FieldContainer>
);
Enter fullscreen mode Exit fullscreen mode

This is the how InputFieldImage is called from its stateful parent component. Link to source.

<InputFieldImage
  title="Change Photo"
  value={image}
  id="upload-photo"
  type="file"
  accept="image/png, image/jpeg"
  onChange={this.imageChangeHandler}
/>
Enter fullscreen mode Exit fullscreen mode

Now all we need to care about is that onChange handler, imageChangeHandler, which goes like this. You can display beautiful toasts using the imageError dialogs we've provided, to increase user experience. Link to source.

imageChangeHandler = e => {
  const imageFile = e.target.files[0];

  if (!imageFile) {
    this.setState({ imageError: "Please select image. " });
    return false;
  }

  if (!imageFile.name.match(/\.(jpg|jpeg|png|gif)$/)) {
    this.setState({ imageError: "Please select a valid image." });
    return false;
  }

  // Utils function
  imageUpload(imageFile, url => {
    this.setState(state => ({
      ...state,
      profile: {
        ...state.profile,
        image: url,
      },
    }));
  });
};
Enter fullscreen mode Exit fullscreen mode

Here, imageUpload is an utils function that handles the post request work to Cloudinary and then runs our this.setState inside its callback which then passes the fetched image url as a prop to InputFieldImage component. This is how our image is displayed on the box after its uploaded.

Getting the Cloudinary Endpoint

Once you logged in, this is how you're dashboard will look like.

Cloudinary Dashboard

And your endpoint will be something in terms of this: https://api.cloudinary.com/v1_1/:cloud_name/:action

Our action here would be /image/upload as we're uploading images and cloud name will be as shown in your dashboard.

One last thing we need is an upload preset, which we'll pass with our FormData object, it'll define default behavior of your uploads. You can create/get one inside Settings → Upload then scroll down to upload presets.

Upload Preset screenshot

If you're creating one, you can select signing mode as Unsigned. This will allow you to perform uploads directly from the browser without going through your servers. Once it's done, hit save and you're preset name will appear as shown above.

Making the upload request

As discussed, we need to create our imageUpload utils function now. Link to Source.

import axios from "axios";

const imageUpload = (imageFile, callback) => {
  const formData = new FormData();

  formData.append("file", imageFile);
  formData.append(
    "upload_preset",
    process.env.REACT_APP_CLOUDINARY_UPLOAD_PRESET
  );

  axios
    .post(
      `https://api.cloudinary.com/v1_1/${process.env.REACT_APP_CLOUDINARY_CLOUD_NAME}/image/upload`,
      formData
    )
    .then(res => res.data.secure_url)
    .then(url => callback(url))
    .catch(err => new Error(err));
};

export default imageUpload;
Enter fullscreen mode Exit fullscreen mode

This function takes, imageFile from our component and the upload_preset we get above, then appends it to the FormData object which is then passed along with the post request to our endpoint. We also pass a callback function that is called after the image link is obtained, where the state is changed and new image link is passed on as prop to InputFieldImage.

Cloudinary Upload Widget

This is a great feature that you can take advantage of. It shows an upload widget which allows you to upload files from various sources, like Dropbox or Google Drive. You can also add it to your project according to requirements. You can refer the official docs or this blog for clarification with React.

Cloudinary Image Upload Widget

Although I haven't used any transformations in my example, but you can absolutely use them if you want to crop or do some fancy edits, all you have to do is add your transformation to end of your request endpoint. Or if you want the edits to happen by default you can do so while setting your upload preset.

This is what an endpoint will look like if you want to crop an image. Refer docs for more.

https://res.cloudinary.com/demo/image/upload/w_200,h_150,c_crop/sample.jpg

Conclusion

Cloudinary provides many more powerful features like video compressing for fast loading and robust transformations. It also has a wide range of integrations for use with any platform of your choice. You can have all information on their homepage. It's free account gives 25 credits which allows for approx 1GB of storage (check pricing). You can see all your uploads inside Media Library.

Have a great day :)

Top comments (0)