0

I'm trying to make a file uploader in ReactJS. I managed to get it all done, except for the part that I show the image to the user. I'm able to make the name show up, but the image does not appear.

I think it's going to be easier if I show the code, so, here it goes

FileUploader Component

import React, { useState } from 'react';
import axios from 'axios'

function FileUploader() {

  const [file, setFile] = useState('')
  const [fileName, setFileName] = useState('Choose File')
  const [selectedFile, setSelectedFile] = useState({
    filePath: '',
    fileName: ''
  })

  const handleChange = e => {
    setFile(e.target.files[0])
    setFileName(e.target.files[0].name)
  }

  const handleUpload = async e => {
    e.preventDefault()

    const data = new FormData()
    data.append('file', file)

    const res = await axios.post('http://localhost:8000/upload', data)

    const { path, originalname } = res.data

   setSelectedFile({filePath: path, fileName: originalname})
  }


  return (
      <>
        <div className="custom-file mb-4">
            <input type="file" className="custom-file-input" id="customFile" onChange={handleChange} />
            <label className="custom-file-label" htmlFor="customFile">{fileName}</label>
        </div>

        <button onClick={handleUpload} className='btn btn-primary btn-block mt-4'>Upload</button>

        {selectedFile.filePath !== '' ? (
          <div className='row mt-5'>
            <div className='col-md-6 m-auto'>
              <h3 className='text-center'>{selectedFile.fileName}</h3>
              <img style={{ width: '100%' }} src={selectedFile.filePath} alt='' />
            </div>
          </div>
        ) : null}
      </>  
    );
}

export default FileUploader;
1
  • 1
    Are you able to load the image in browser by directly accessing the value of filepath? Commented Jun 26, 2020 at 12:46

2 Answers 2

1

I think you should use blob image by using URL.createObjectUrl

Below is updated code

import React, { useState } from 'react';
import axios from 'axios'

function FileUploader() {

  const [file, setFile] = useState('')
  const [fileName, setFileName] = useState('Choose File')
  const [selectedFile, setSelectedFile] = useState({
    filePath: '',
    fileName: ''
  })
  const [blobImage, setBlobImage] = useState() // <= add

  const handleChange = e => {
    setFile(e.target.files[0])
    setFileName(e.target.files[0].name)
    setBlobImage(URL.createObjectURL(e.target.files[0])) // <= add
  }

  const handleUpload = async e => {
    e.preventDefault()

    const data = new FormData()
    data.append('file', file)

    const res = await axios.post('http://localhost:8000/upload', data)

    const { path, originalname } = res.data

   setSelectedFile({filePath: path, fileName: originalname})
  }


  return (
      <>
        <div className="custom-file mb-4">
            <input type="file" className="custom-file-input" id="customFile" onChange={handleChange} />
            <label className="custom-file-label" htmlFor="customFile">{fileName}</label>
        </div>

        <button onClick={handleUpload} className='btn btn-primary btn-block mt-4'>Upload</button>

        {selectedFile.filePath !== '' ? (
          <div className='row mt-5'>
            <div className='col-md-6 m-auto'>
              <h3 className='text-center'>{selectedFile.fileName}</h3>
              <img style={{ width: '100%' }} src={blobImage} alt='' /> // <= change src to blobImage
            </div>
          </div>
        ) : null}
      </>  
    );
}

export default FileUploader;
Sign up to request clarification or add additional context in comments.

2 Comments

OPs approach involves rendering the image using the url received in the response of upload api. Your approach might work in loading the image, but it still is an overkill as the upload api is expected to host the image anyways.
@DhruvShah I think the requirement is to show the selected image, I don't the response data is needed over here, in this case.
0

I wrote an article about file uploading with React and DnD but it's not that far off from what you're trying to accomplish:

Build A React Drag & Drop Progress File Uploader

My guess is that you're wanting to display the file preview of the image that is about to be uploaded. You can do this by loading the image into the local state, although you'll have to be careful if it's a large image as it can crash the browser.

Click the "Run code snippet" to see it in action.

// main.js
const { useState } = React;

const App = () => {
  // State / Props
  const [preview, setPreview] = useState(null);
  
  // Functions
  const onInputFileChange = event => {
    // reset each time
    setPreview(null);
    
    // Define supported mime types
    const supportedFilesTypes = ['image/jpeg', 'image/png'];
    
    if (event.target.files.length > 0) {
      // Get the type of the first indexed file
      const { type } = event.target.files[0];

      if (supportedFilesTypes.indexOf(type) > -1) {
        const reader = new FileReader();
        reader.onload = e => { setPreview(e.target.result); };
        reader.readAsDataURL(event.target.files[0]);
      }
    }
  };
  
  return (<div><h1>Choose an image</h1><input onChange={onInputFileChange} type="file" name="file" />{preview && <img src={preview} />}</div>);
};


ReactDOM.render(<App />, document.getElementById('root'));
<body>
<div id="root"></div>

<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>

<script type="text/babel" src="main.js"></script>
</body>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.