简体   繁体   中英

Upload and read a file in react

Im trying to upload a file with React and see its contents, but what it gives me is C:\\fakepath\\ . I know why it gives fakepath , but what is the correct way to upload and read the contents of a file in react?

<input type="file"
      name="myFile"
      onChange={this.handleChange} />

handleChange: function(e) {
        switch (e.target.name) {
        case 'myFile':
            const data = new FormData();
            data.append('file', e.target.value);
            console.log(data);
        default:
            console.error('Error in handleChange()'); break;
        }
    },

To get the file info you want to use event.target.files which is an array of selected files. Each one of these can be easily uploaded via aFormData object. See below snippet for example:

 class FileInput extends React.Component { constructor(props) { super(props) this.uploadFile = this.uploadFile.bind(this); } uploadFile(event) { let file = event.target.files[0]; console.log(file); if (file) { let data = new FormData(); data.append('file', file); // axios.post('/files', data)... } } render() { return <span> <input type="file" name="myFile" onChange={this.uploadFile} /> </span> } } ReactDOM.render(<FileInput />, document.getElementById('root'));
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.1/react.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.1/react-dom.min.js"></script> <div id="root"></div>

You may want to look into FileReader which can help if you want to handle the file on the client side, for example to display an image.

https://developer.mozilla.org/en-US/docs/Web/API/FileReader

You can use React Dropzone Uploader , which gives you file previews (including image thumbnails) out of the box, and also handles uploads for you.

In your onChangeStatus prop you can react to the file's meta data and the file itself, which means you can do any kind of client-side processing you want before or after uploading the file.

import 'react-dropzone-uploader/dist/styles.css'
import Dropzone from 'react-dropzone-uploader'

const Uploader = () => {  
  return (
    <Dropzone
      getUploadParams={() => ({ url: 'https://httpbin.org/post' })} // specify upload params and url for your files
      onChangeStatus={({ meta, file }, status) => { console.log(status, meta, file) }}
      onSubmit={(files) => { console.log(files.map(f => f.meta)) }}
      accept="image/*,audio/*,video/*"
    />
  )
}

Uploads have progress indicators, and they can be cancelled or restarted. The UI is fully customizable.

Full disclosure: I wrote this library.

Try to use Multer and gridfs-storage on the back end and store the fileID along with your mongoose schema.

// Create a storage object with a given configuration
const storage = require('multer-gridfs-storage')({
  url: 'MONGOP DB ATLAS URL'
});

// Set multer storage engine to the newly created object
const upload = multer({ storage }).single('file');

router.post('/', upload, (req, res) => {

  const newreminder = new Reminders({
    category: req.body.category,
    name:req.body.name,
    type: req.body.type,
    exdate: req.body.exdate,
    location:req.body.location,
    notes:req.body.notes,
    fileID: req.file.id
  });
  newreminder.save(function(err){
    if(err){
      console.log(err);
      return;
    }

    res.json({ "success": "true"});
  });

});

Then on the front end treat it normally (with Axios) and upload the entire file and grab a hold of all the info in the normal react way:

onSubmit = (e) => {
  e.preventDefault;
  const formData = new FormData();
  formData.append({ [e.target.name]: e.target.value })
  formData.append('file', e.target.files[0]);

  axios.post({
    method:'POST',
    url:'EXPRESS JS POST REQUEST PATH',
    data: formData,
    config:{ headers: {'Content-Type':'multipart/form-data, boundary=${form._boundary}'}}
  })
  .then(res => console.log(res))
  .catch(err => console.log('Error', err))
}

Have you use dropzone ? see this react-dropzone

easy implement, upload and return url if this important.

onDrop: acceptedFiles => {
    const req = request.post('/upload');
    acceptedFiles.forEach(file => {
        req.attach(file.name, file);
    });
    req.end(callback);
}

You can use FileReader onload methods to read the file data and then can send it to the server.

You can find this useful to handle files using File Reader in React ReactJS File Reader

To add to the other answers here, especially for anyone new to React, it is useful to understand that react handles forms a little differently than people may be used to.

At a high level, react recommends using 'Controlled components" :

In most cases, we recommend using controlled components to implement forms. In a controlled component, form data is handled by a React component. The alternative is uncontrolled components, where form data is handled by the DOM itself.

This essentially means that the user input, eg a text field, is also a state of the component and as the user updates it the state is updated and the value of the state if displayed in the form. This means the state and the form data are always in synch.

For an input type of file this will not work because the file input value is read-only. Therefore, a controlled component cannot be used and an 'uncontrolled component' is used instead.

In React, an is always an uncontrolled component because its value can only be set by a user, and not programmatically.

The recommended way to input a file type (at the time of writing) is below, from the react documentation here https://reactjs.org/docs/uncontrolled-components.html#the-file-input-tag :

class FileInput extends React.Component {
  constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.fileInput = React.createRef();
  }
  handleSubmit(event) {
    event.preventDefault();
    alert(
      `Selected file - ${this.fileInput.current.files[0].name}`
    );
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Upload file:
          <input type="file" ref={this.fileInput} />
        </label>
        <br />
        <button type="submit">Submit</button>
      </form>
    );
  }
}

ReactDOM.render(
  <FileInput />,
  document.getElementById('root')
);

The documentation includes a codepen example which can be built on.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM