19

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; } }, 

6 Answers 6

16

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 a FormData 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

Sign up to request clarification or add additional context in comments.

4 Comments

how can i read the file's data after uploading it? @Purgatory
Surely you would handle that server side, I don't know what you are uploading nor what code you have server side. You should create a new question if you need help with server side code.
@Purgatory the question obviously was about processing the contents of the file on the client side before submitting it.
@artshpakov thanks for the attitude, but you can clearly see that I have touched on it at the bottom of my answer.
4

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.

3 Comments

Your example only uses console log, as does the example in the docs. It's unclear if work is going on behind the scenes, or if full upload and onChange functions need to be coded. If the upload and change functions need to be coded, then this doesn't really answer the question, which would be answered by providing the code that goes in those functions.
can we use this for excel/csv files?
This doesn't explain whether you can read the file stream from the uploaded file. AFAICT this just grabs the file which you can pass to a POST.
2

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)) } 

1 Comment

How would you manage the onChange method? Don't you have to store the values in state in order to be able to submit the data to X database?
1

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

Comments

0

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); } 

Comments

0

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, e.g. 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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.