Get a preview image before uploading to React

There are many examples of this here, but I can not find a single one for the reaction. I was able to convert vanilla js so that it responds but got an error .

The answer looks quite simple, so here I react:

getInitialState: function(){ return{file: []} }, _onChange: function(){ // Assuming only image var file = this.refs.file.files[0]; var reader = new FileReader(); var url = reader.readAsDataURL(file); console.log(url) // Would see a path? // TODO: concat files for setState }, render: function(){ return( <div> <form> <input ref="file" type="file" name="user[image]" multiple="true" onChange={this._onChange}/> </form> {/* Only show first image, for now. */} <img src={this.state.file[0} /> </div> ) }; 

Basically, all the answers I saw show something like what I have. Is there a difference in a React app?

Regarding the answer:

enter image description here

+14
source share
5 answers

It makes no difference, just read your image when the load event ends. In the load end event handler, just specify your state:

 getInitialState: function(){ return{file: []} } _onChange: function(){ // Assuming only image var file = this.refs.file.files[0]; var reader = new FileReader(); var url = reader.readAsDataURL(file); reader.onloadend = function (e) { this.setState({ imgSrc: [reader.result]; }) }.bind(this); console.log(url) // Would see a path? // TODO: concat files }, render: function(){ return( <div> <form> <input ref="file" type="file" name="user[image]" multiple="true" onChange={this_onChange}/> </form> {/* Only show first image, for now. */} <img src={this.state.imgSrc} /> </div> ) } 
+23
source

Here is a simple and working solution that displays all selected images

 getInitialState: function(){ return{file: []} } _onChange: (event)=>{ this.setState({ imgs: event.target.files }) }, render: function(){ return( <div> <form> <input ref="file" type="file" name="user[image]" multiple="true" onChange={this._onChange}/> </form> {/* Display all selected images. */} {this.state.imgs && [...this.state.imgs].map((file)=>( <img src={URL.createObjectURL(file)} /> ))} </div> ) } 
+5
source

Extending Cels' answer and avoiding memory leaks with createObjectURL when @El Anonimo warns about , we could use useEffect to create a preview and clean up after unmounting a component like this

 useEffect(() => { // create the preview const objectUrl = URL.createObjectURL(selectedFile) setPreview(objectUrl) // free memory when ever this component is unmounted return () => URL.revokeObjectURL(objectUrl) }, [selectedFile]) 

The full code might look something like this

 export const ImageUpload = () => { const [selectedFile, setSelectedFile] = useState() const [preview, setPreview] = useState() // create a preview as a side effect, whenever selected file is changed useEffect(() => { if (!selectedFile) { setPreview(undefined) return } const objectUrl = URL.createObjectURL(selectedFile) setPreview(objectUrl) // free memory when ever this component is unmounted return () => URL.revokeObjectURL(objectUrl) }, [selectedFile]) const onSelectFile = e => { if (!e.target.files || e.target.files.length === 0) { setSelectedFile(undefined) return } // I've kept this example simple by using the first image instead of multiple setSelectedFile(e.target.files[0]) } return ( <div> <input type='file' onChange={onSelectFile} /> {selectedFile && <img src={preview} /> } </div> ) } 
+1
source

There is my decision. Very simple and easy to use.

Jsx

 <form onSubmit={this.onSubmit} > <input ref="uploadImg" type="file" name="selectedFile" onChange={this._onChange} /> </form> <img src={this.state.imageUrl} /> 

And function

  _onChange = (e) => { const file = this.refs.uploadImg.files[0] const reader = new FileReader(); reader.onloadend = () => { this.setState({ imageUrl: reader.result }) } if (file) { reader.readAsDataURL(file); this.setState({ imageUrl :reader.result }) } else { this.setState({ imageUrl: "" }) } } 

And, of course, you need to have a state like imageUrl , which is our src in jsx.

0
source

I was madly trying to get this to work with multiple files, so if anyone else has this problem, here you go:

 const onFileChange = e => { e.preventDefault(); const filesList = e.target.files; if (filesList.length === 0) return; //Spread array to current state preview URLs let arr = [...data.imagePreviewUrls]; for (let i = 0; i < filesList.length; i++) { const file = filesList[i]; const reader = new FileReader(); reader.onload = upload => { //push new image to the end of arr arr.push(upload.target.result); //Set state to arr setData({ ...data, imagePreviewUrls: arr }); }; reader.readAsDataURL(file); } }; 

In fact, the for loop resolves before even the first onload event fires, resetting the state at each iteration. To solve this problem, simply create an array outside the for loop and load a new element into it. This will process multiple files, even if the user closes the file dialog box, and then decides to download more if the status has not been reset.

0
source

All Articles