2020-05-11
|~3 min read
|467 words
Recently, I’ve been exploring Cloudinary’s API and thinking about different ways to take advantage of their service.
The example I’ve been building on is a form where the user uploads an image.
Now that that they’ve selected an image, I want to allow them to preview it before submitting.
In writing about uploading images To Cloudinary, I noted that the JSON response from Cloudinary includes a URL to the image.
This makes conditionally rendering the preview image a matter of short-circuiting (see my previous post for more on conditionally rendering in React).
In this example, we’re using the CreateItem
component originally written for uploading images to Cloudinary:
export class CreateItem extends React.Component {
state = {
/*...*/
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label htmlFor="file">
Image
<input
type="file"
id="file"
name="file"
placeholder="Upload an image"
required
onChange={this.handleImageUpload}
/>
{this.state.image && (
<img src={this.state.image} width={200} alt="Upload Preview" />
)}
</label>
</form>
)
}
}
But wait, in a follow up article, I chose to defer uploading images to Cloudinary as long as possible to avoid unnecessary / wasteful network usage.
Does this mean that there’s no way to offer a preview of an uploaded file? Fortunately, the answer’s no!
Stack Overflow provides some excellent answers in this conversation on Previewing an image before it’s uploaded
My preferred answer comes from @nkron:
There are a couple ways you can do this. The most efficient way would be to use URL.createObjectURL() on the File from your <input>. Pass this URL to img.src to tell the browser to load the provided image.
(This is actually a similar approach I used previously to create downloadable files.)
Let’s put this into practice by modifying the CreateItem
class we defined here.
Add a tempUrl
property to state within our handleImageUpload
function.1
Once that’s saved, we can point to that URL to render the image.
export class CreateItem extends React.Component {
state = {
/*...*/
}
handleImageUpload = (event) => {
const { files } = event.target
const tempUrl = URL.createObjectURL(files[0]) this.setState({ files, tempUrl })
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label htmlFor="file">
Image
<input
type="file"
id="file"
name="file"
placeholder="Upload an image"
required
onChange={this.handleImageUpload}
/>
{this.state.image && (
<img
src={this.state.tempUrl} width={200}
alt="Upload Preview"
/>
)}
</label>
</form>
)
}
}
As @tfmontague points out, this URL is temporary: it’s saved in the browser cache and should not be treated as a persistent location. Keeping the file around helps to make sure that when we’re ready to submit we are able to save the actual file.
Hi there and thanks for reading! My name's Stephen. I live in Chicago with my wife, Kate, and dog, Finn. Want more? See about and get in touch!