How to reset ReactJS file input

HtmlReactjsFile Upload

Html Problem Overview


I have file upload input:

<input onChange={this.getFile} id="fileUpload" type="file" className="upload"/>

And I handle upload this way:

getFile(e) {
    e.preventDefault();
    let reader = new FileReader();
    let file = e.target.files[0];
    reader.onloadend = (theFile) => {
        var data = {
            blob: theFile.target.result, name: file.name,
            visitorId:  this.props.socketio.visitorId
        };
        console.log(this.props.socketio);
        this.props.socketio.emit('file-upload', data);
    };
    reader.readAsDataURL(file);
}

If I upload same file twice, then upload event is not fired. How can I fix that? For simple js code it was enough to do the following: this.value = null; in change handler. How can I do it with ReactJS?

Html Solutions


Solution 1 - Html

I think you can just clear the input value like this :

e.target.value = null;

File input cannot be controlled, there is no React specific way to do that.


Edit For old browsers (one of the following techniques.

See http://jsbin.com/zurudemuma/1/edit?js,output (tested on IE10 & 9)

Solution 2 - Html

What worked for me was setting a key attribute to the file input, then when I needed to reset it I update the key attribute value:

functionThatResetsTheFileInput() {
  let randomString = Math.random().toString(36);

  this.setState({
    theInputKey: randomString
  });
}

render() {
  return(
    <div>
      <input type="file"
             key={this.state.theInputKey || '' } />
      <button onClick={this.functionThatResetsTheFileInput()} />
    </div>
  )
}

That forces React to render the input again from scratch.

Solution 3 - Html

This work for me - ref={ref => this.fileInput = ref}

<input id="file_input_file" type="file" onChange={(e) => this._handleFileChange(e)} ref={ref=> this.fileInput = ref} />

then in my case once the file was uploaded to the server , I clear it by using the statement below

 this.fileInput.value = "";

Solution 4 - Html

I do it by updating key inside my file input. This will force a re-render and previously selected file will go away.

<input type="file" key={this.state.inputKey} />

Changing the state inputKey will re-render the component. One way to change the inputKey will be to always set it to Date.now() on click of a button which is supposed to clear the field.

Solution 5 - Html

With every click onClick you can reset the input, so that even with the same file onChange will be triggered.

<input onChange={this.onChange} onClick={e => (e.target.value = null)} type="file" />

Solution 6 - Html

The following worked for me using React Hooks. This is done using what is known as a "controlled input". That means, the inputs are controlled by state, or their source of truth is state.

TL;DR Resetting the file input was a two-step process using both the useState() and useRef() hooks.

NOTE: I also included how I reset a text input in case anyone else was curious.

function CreatePost({ user }) {
    const [content, setContent] = React.useState("");
    const [image, setImage] = React.useState(null); //See Supporting Documentation #1
    const imageInputRef = React.useRef(); //See Supporting Documentation #2

    function handleSubmit(event) {
        event.preventDefault(); //Stop the pesky default reload function
        setContent(""); //Resets the value of the first input - See #1

        //////START of File Input Reset
        imageInputRef.current.value = "";//Resets the file name of the file input - See #2
        setImage(null); //Resets the value of the file input - See #1
        //////END of File Input Reset
    }

    return (
    <div>
        <form onSubmit={handleSubmit}>
            <input 
            type="text" 
            placeholder="Add Post Content" 
            onChange={event => setContent(event.target.value)}
            value={content} //Make this input's value, controlled by state
            />
            <input 
            type="file"
            onChange={event => setImage(event.target.files[0])} //See Supporting Doc #3
            ref={imageInputRef} //Apply the ref to the input, now it's controlled - See #2
            />
            <button type="submit">Submit Form</button>
        </form>
    </div>
    )
};

Supporting Documentation:

  1. useState Hook
  • Returns a stateful value, and a function to update it.
  1. useRef Hook
  • If you pass a ref object to React, React will set its current property to the corresponding DOM node whenever that node changes.
  1. Using files from web apps
  • If the user selects just one file, it is then only necessary to consider the first file of the list.

Solution 7 - Html

You can also include this in your input element if you know you are not going to be using the built-in file input value at all.

<input value={""} ... />

This way the value is always reset to the empty string on render and you don't have to include it awkwardly in an onChange function.

Solution 8 - Html

import React, { useRef } from "react";

export default function App() {
  const ref = useRef();

  const reset = () => {
    ref.current.value = "";
  };

  return (
    <>
      <input type="file" ref={ref} />
      <button onClick={reset}>reset</button>
    </>
  );
}

Solution 9 - Html

I know file input is always uncontrolled however the following code still works in my own porject, I can reset the input with no problems at all.

constructor(props) {
    super(props);
    this.state = {
        selectedFile: undefined,
        selectedFileName: undefined,
        imageSrc: undefined,
        value: ''
    };

    this.handleChange = this.handleChange.bind(this);
    this.removeImage = this.removeImage.bind(this);
}

handleChange(event) {
    if (event.target.files[0]) {
        this.setState({
            selectedFile: event.target.files[0],
            selectedFileName: event.target.files[0].name,
            imageSrc: window.URL.createObjectURL(event.target.files[0]),
            value: event.target.value,
        });
    }
}

// Call this function to reset input
removeImage() {
    this.setState({
        selectedFile: undefined,
        selectedFileName: undefined,
        imageSrc: undefined,
        value: ''
    })
}

render() {
    return (
        <input type="file" value={this.state.value} onChange={this.handleChange} />
    );
}

Solution 10 - Html

We can reset file input by using key = {this.state.fileInputKey} and initialsing fileInputKey to Date.now() in constructor state. On file upload success , we need to again assign fileInputKey: Date.now(), so it will have different value than previous and it create new file input component on next render()

We can also do this manually by clicking button to clear/reset file Input

Below is the working code :

import React from "react";
import { Button } from "reactstrap";

class FileUpload extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      selectedFile: null,
      fileInputKey: Date.now(),
      message: ""
    };
    this.handleClear = this.handleClear.bind(this);
    this.onClickHandler = this.onClickHandler.bind(this);
    this.onChangeHandler = this.onChangeHandler.bind(this);
  }

  onChangeHandler = event => {
    this.setState({
      selectedFile: event.target.files
    });
  };

  onClickHandler = () => {
    if (this.state.selectedFile === null) {
      this.setState({
        message: "Please select File"
      });
      return;
    }
    //axios POST req code to send file to server
    {
      /**        
         const data = new FormData()
    data = this.state.selectedFile[0]                
      axios.post("http://localhost:8080/api/uploadFile/", data)
               .then(res => { 
             if (res.status == 200) {
           // upload success
             }                
               })
               .catch(err => { 
                  //message upload failed
               })    
    */
    }
//after upload to server processed

    this.setState({
      selectedFile: null,
      fileInputKey: Date.now(),
      message: "File Uploaded"
    });
  };

  handleClear() {
    this.setState({
      selectedFile: null,
      fileInputKey: Date.now(),
      message: ""
    });
  }

  render() {
    return (
      <div>
        <input
          type="file"
          key={this.state.fileInputKey}
          class="form-control"
          onChange={this.onChangeHandler}
        />
        <button
          type="button"
          class="btn btn-success btn-block"
          onClick={this.onClickHandler}
        >
          Upload
        </button>
        <Button
          type="button"
          value="Clear"
          data-test="clear"
          onClick={this.handleClear}
        >
          {" "}
          Clear{" "}
        </Button>

        <br />
        <label>{this.state.message}</label>
      </div>
    );
  }
}

export default FileUpload;

Solution 11 - Html

Here is my solution using redux form

class FileInput extends React.Component {
  constructor() {
    super();

    this.deleteImage = this.deleteImage.bind(this);
  }

  deleteImage() {
    // Just setting input ref value to null did not work well with redux form
    // At the same time just calling on change with nothing didn't do the trick
    // just using onChange does the change in redux form but if you try selecting
    // the same image again it doesn't show in the preview cause the onChange of the
    // input is not called since for the input the value is not changing
    // but for redux form would be.

    this.fileInput.value = null;
    this.props.input.onChange();
  }

  render() {
    const { input: { onChange, value }, accept, disabled, error } = this.props;
    const { edited } = this.state;

    return (
      <div className="file-input-expanded">
        {/* ref and on change are key properties here */}
        <input
          className="hidden"
          type="file"
          onChange={e => onChange(e.target.files[0])}
          multiple={false}
          accept={accept}
          capture
          ref={(input) => { this.fileInput = input; }}
          disabled={disabled}
        />
        {!value ?
          {/* Add button */}
          <Button
            className="btn-link action"
            type="button"
            text="Add Image"
            onPress={() => this.fileInput.click()}
            disabled={disabled}
          />
          :
          <div className="file-input-container">
            <div className="flex-row">
              {/* Image preview */}
              <img src={window.URL.createObjectURL(value)} alt="outbound MMS" />
              <div className="flex-col mg-l-20">
                {/* This button does de replacing */}
                <Button
                  type="button"
                  className="btn-link mg-b-10"
                  text="Change Image"
                  onPress={() => this.fileInput.click()}
                  disabled={disabled}
                />
                {/* This button is the one that does de deleting */}
                <Button
                  type="button"
                  className="btn-link delete"
                  text="Delete Image"
                  onPress={this.deleteImage}
                  disabled={disabled}
                />
              </div>
            </div>
            {error &&
              <div className="error-message"> {error}</div>
            }
          </div>
        }
      </div>
    );
  }
}

FileInput.propTypes = {
  input: object.isRequired,
  accept: string,
  disabled: bool,
  error: string
};

FileInput.defaultProps = {
  accept: '*',
};

export default FileInput;

Solution 12 - Html

In my case I had a functional component and after selecting a file it suppose to set the file name in the state so using any solution above was failing except the ref one which i fixed like this.

const fileUpload = props => {

	const inputEl = useRef(null)
	const onUpload = useCallback(e => {
         uploadFile(fileDetails)
            .then(res => {
    			 inputEl.current.value = ''  
            })
            .catch(err => {
       			 inputEl.current.value = ''
            })
	})
	
	return (
		<input type='file' ref={inputEl} onChange={handleChange} />
		<Button onClick={onUpload}>Upload</Button>
	)
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionStepan YakovenkoView Question on Stackoverflow
Solution 1 - HtmlFreezView Answer on Stackoverflow
Solution 2 - HtmlTonatiuhView Answer on Stackoverflow
Solution 3 - HtmlJozcarView Answer on Stackoverflow
Solution 4 - HtmlaelorView Answer on Stackoverflow
Solution 5 - HtmlElnoorView Answer on Stackoverflow
Solution 6 - HtmlDani AmsalemView Answer on Stackoverflow
Solution 7 - HtmlIRTrapGodView Answer on Stackoverflow
Solution 8 - HtmlPoojaView Answer on Stackoverflow
Solution 9 - HtmlJack L.View Answer on Stackoverflow
Solution 10 - HtmlVivek BariView Answer on Stackoverflow
Solution 11 - HtmlAgustina ChaerView Answer on Stackoverflow
Solution 12 - Htmldev_khanView Answer on Stackoverflow