- Image Upload and Manipulation with React
- This article is authorized by original author Damon Bauer
- The Nuggets translation Project
- Translator: DeadLion
- Proofreader: Mypchas6fans, Kulbear
The following guest article was written byDamon BauerFinished, the topic is about a very common job for Web developers: providing users with the ability to upload images. I’d say it’s not easy, but with some powerful tools to help do some of the “heavy” work, the task feels a lot easier than it used to. Damon even did it all in a browserThe task!
Enabling users to upload images is a common thing for Web developers. It may seem like a piece of cake at first, but there are a few issues to consider when actually creating an image upload component. Here are some things to look out for:
- What types of images are allowed to upload?
- How big a picture do you need? How does this affect performance?
- What is the ratio of length to width?
- How to manage images? Can you catch bad pictures?
- Where are the images stored? How to operate and maintain?
Server-side tools such as Paperclip and ImageProcessor solve most of these problems. Unfortunately, there is no off-the-shelf tool for single-page applications. I’ll show you how I solved this problem in a React application, using no server-side language at all.
This is a small sample of the application we’re going to build.
kit
I used the following three tools:
- React-dropzone accepts images from the user
- Superagent converts uploaded images
- Cloudinary stores and edits images.
Set the Cloudinary
Cloudinary is a cloud service that provides storage, manipulation, management and functionality for images. I chose Cloudinary because it offers a free account with all the features I need. You’ll need at least a free account to get started.
Let’s say you want to crop, resize and add filters to uploaded images. Cloudinary has a conversion concept that is linked to the ability to modify images, whether you need it or not. Once uploaded, the new image is converted, modified, and then stored.
In Cloudinary control panel, go to Settings > Upload, and select “Add Upload preset” under “Upload Presets”.
Next, change Mode to “Unsigned”. This is necessary, and then you can upload the private key directly to Cloudinary without having to use the server-side language to process it.
You can add any Transformations by selecting Edit in the Incoming and Transformations section. You can crop, resize, change quality, rotate, filter, and so on. Save the preset and that’s it! You now have a place to upload, process, and store images for your application. Note the default name, which we will use later. Let’s get into the code.
Accept user input
To handle image uploads, I use the React-Dropzone plugin. It includes features such as drag-and-drop files, file type restrictions, and multiple file uploads.
First, install dependencies. Enter the following command on the command line to run:
npm install react react-dropzone superagent --saveCopy the code
Then import React, react-DropZone, and superAgent into your component. I use the ES6 import syntax.
import React from 'react';
import Dropzone from 'react-dropzone';
import request from 'superagent';Copy the code
We’ll use the Superagent later. Now include a react-Dropzone instance in your component’s Render method.
export default class ContactForm extends React.Component {
render() {
<Dropzone
multiple={false}
accept="image/*"
onDrop={this.onImageDrop.bind(this)}>
<p>Drop an image or click to select a file to upload.</p>
</Dropzone>
}Copy the code
Here are some summaries of this component:
multiple={false}
Only one image can be uploaded at a time.accept="image/*"
Any type of image is allowed. You can explicitly limit file types to only certain types that can be uploaded, for exampleaccept="image/jpg,image/png"
.onDrop
Is a method that is triggered when an image is uploaded.
When using the React ES5 class syntax (React. CreateClass), all methods are “autobound” to class instances. The code in this article uses an ES6 class syntax (extends React.Component) and does not provide automatic binding. So we used.bind(this) in the onDrop property. (If you’re not familiar with.bind, check out this article.)
Handle drag and drop images
Now, let’s set up a way to do something when uploading an image.
First, set a const for the two important upload messages.
- Upload default ID (automatically generated when you create an upload default)
- Your Cloudinary upload URL
// import statements
const CLOUDINARY_UPLOAD_PRESET = 'your_upload_preset_id';
const CLOUDINARY_UPLOAD_URL = 'https://api.cloudinary.com/v1_1/your_cloudinary_app_name/upload';
export default class ContactForm extends React.Component {
// render()Copy the code
Then, add a record to the component initialization state (using this.setState); I gave a name to this attribute uploadedFileCloudinaryUrl. Finally, this will hold an image URL generated by Cloudinary after a successful upload. We’re going to use this state later.
export default class ContactForm extends React.Component {
constructor(props) {
super(props);
this.state = {
uploadedFileCloudinaryUrl: ' '
};
}Copy the code
The react-Dropzone documentation says it always returns an array of uploaded files, so we pass that array to the files parameter of the onImageDrop method. We set it to one image at a time, so the image is always first in the array.
Call handleImageUpload and pass the image (files[0]) into this method. I separated this approach into a separate approach, following the single responsibility principle. In essence, this principle approach teaches you to keep your approach compact and do only one thing.
export default class ContactForm extends React.Component {
constructor(props) { . }
onImageDrop(files) {
this.setState({
uploadedFile: files[0]}); this.handleImageUpload(files[0]);
}
render() { .}}Copy the code
Handle image upload and conversion
First, use the SuperAgent to POST the two const values we set earlier to Cloudinary. The.field method lets us attach data to a POST request. This data contains all the information Cloudinary processes when uploading images. By calling.end, the request is executed and the callback is provided.
export default class ContactForm extends React.Component {
constructor(props) { . }
onImageDrop(files) { . }
handleImageUpload(file) {
let upload = request.post(CLOUDINARY_UPLOAD_URL)
.field('upload_preset', CLOUDINARY_UPLOAD_PRESET)
.field('file', file);
upload.end((err, response) => {
if (err) {
console.error(err);
}
if(response.body.secure_url ! = =' ') { this.setState({ uploadedFileCloudinaryUrl: response.body.secure_url }); }}); } render() {.}}Copy the code
In the.end callback, it is a good idea to print all returned errors while also telling the user that an error has occurred.
Next, we receive a response that contains a URL and check if it is an empty string. This is the URL Cloudinary generates when the image is uploaded and processed. For example, if a user is editing their profile and uploads an image, you can save the new image URL returned by Cloudinary to your database.
The code we’re currently writing allows the user to drag and drop an image, and the component sends the image to Cloudinary and receives a transformed image URL for us to use.
Rendering phase
The last part of the component is a div that previews the uploaded image.
export default class ContactForm extends React.Component {
constructor(props) { . }
onImageDrop(files) { . }
handleImageUpload(file) { . }
render() {
<div>
<div className="FileUpload">
.
</div>
<div>
{this.state.uploadedFileCloudinaryUrl === ' ' ? null :
<div>
<p>{this.state.uploadedFile.name}</p>
<img src={this.state.uploadedFileCloudinaryUrl} />
</div>}
</div>
</div>
}Copy the code
If uploadedFileCloudinaryUrl state is an empty string, the ternary operator will output a null (nothing). Recall, the components of uploadedFileCloudinaryUrl state by default is an empty string; This means that when the component renders, the div will be empty.
However, when Cloudinary returns a URL, state is no longer an empty string because we updated state in handleImageUpload. At this point, the component will re-render, showing a preview of the uploaded file name and the transformed image.
The end of the
This is just the groundwork for an image upload component. There are plenty of additional features you could add, like:
This is just preparation for the image upload component. There are many additional features that can be added, such as:
- Allows multiple image uploads
- Clear uploaded images
- If the upload fails for some reason, an error is displayed
- Use the mobile device camera as the upload source
So far, these Settings have worked well for my job. The hard-coded upload presets aren’t perfect, but I haven’t had any problems yet.
Hopefully you already understand how to upload, store, and manipulate images using React without using a server-side language. If you have any questions or comments, I’d love to hear them! I’ve built a repository, and you can click on the link to see the code.