How to reset ReactJS file input
Asked Answered
E

15

131

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?

Eisenstein answered 12/2, 2017 at 19:42 Comment(1)
onChange={this.getFile.bind(this)} or getFile = (e) => {Natividad
N
201

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 (<IE11), you can use one of the following techniques.

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

Neolatin answered 12/2, 2017 at 20:14 Comment(5)
Note: setting undefined in Chrome 79 triggers this error: Uncaught DOMException: Failed to set the 'value' property on 'HTMLInputElement': This input element accepts a filename, which may only be programmatically set to the empty string.. But null doesn't trigger the error.Airwoman
Beware browser incompatibilities on this: #1703728Collen
Thanks @T.J.Crowder, I updated my answer. Even if most of websites stopped supporting those browsers they still exist :)Neolatin
For some reason I thought I'd seen something there saying = null didn't work on IE11, but you're right, it does in IE11. So near-universal (now) in anything people should really need to support.Collen
for typescript a // @ts-ignore is requiredRocaille
G
79

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.

Gemmation answered 23/8, 2017 at 17:44 Comment(8)
To explain how this works, you need to update the this.state.theInputKey when you want to cleat the input. Under the hood, changing the key causes react to re-render the input thus clearing it.Recuperator
I like this idea. Then I can control the input field from other functionalities, which is what I need right now. It works fine. Thanks.Maritamaritain
I like the approach, however I wanted to make this from getDerivedStateFromProps, and fortunately it works there as well, cause we still have access to the state. :)Blameworthy
This worked for me trying to re render react-csv-reader (not an input tag) for the same issue faced. Thanks.Construction
Worked like a charm. I used key={Date.now()}Immersed
Horrible anti-pattern, please don't use this.Ingot
You can simply use key={Math.random()}Blest
I like this idea, although I would use an integer instead and set the state using setState((prevState) => return {inputResetKey: prevState.inputResetKey + 1} });Warman
B
56

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.

Baptlsta answered 3/4, 2019 at 12:39 Comment(2)
This works really well. Also makes it easy to provide some custom feedback to the user. For example: I have one state variable to act as a key (using Date.now() , and use another state variable - set alongside this - to provide a message to the user such as 'successfully uploaded at (time)'.Rock
This works well when you do not want to clear the field when you click on a button, but you want to make sure the field is empty before uploading any other file.Ramires
H
54

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 = "";
Headship answered 6/10, 2017 at 2:5 Comment(3)
I like the approach, however I wanted to make this from getDerivedStateFromProps and unfortunately it won't work, as we don't have access to this there.Blameworthy
This approach works for me I did this in functional React component: const [fileInput_ref, setFileInputRef] = useState({}); and in input itself ref={(ref) => { setFileInputRef(ref) }} and then clear it out. Thanks @HeadshipLupita
If you use forwardRef, its gonna be somewhat like this: fileInputRef.current.value = '';Nefen
I
19
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>
    </>
  );
}
Ileum answered 17/12, 2021 at 8:19 Comment(1)
input:file don't have value attribute Error is popingOrit
C
18

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" />
Chimp answered 31/7, 2019 at 22:8 Comment(0)
T
15

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.
  2. 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.
  3. 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.
Thirzi answered 24/3, 2020 at 5:27 Comment(1)
This should be the accepted answer as this is more React way of resetting the input. I have the input in another component and I could just reset it very easily using useRef. I didn't need to select the input or listen to any events.Evangelineevangelism
U
8

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.

Ultimately answered 8/2, 2019 at 20:25 Comment(0)
S
2

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} />
    );
}
Speaker answered 27/7, 2018 at 12:16 Comment(0)
P
2

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;
Plasmolysis answered 4/6, 2020 at 12:37 Comment(1)
Is very helpful with a clean file button. ThanksOceanid
M
2

I recently got stumbled into this issue to reset the File type input field. I think it is still a milestone for most developers. So I thought I should share my solution.

Since we are listening to the onChange event to update the image file into some of our states, we will have our component rerendered once we set the state. In such case, we can specify the value of the input file as empty like value='' which will cause the input field to reset its value after each change of its value.

 <input  
  type="file"
  value=''
  onChange={onChangeFnc}
 /> 
Moorer answered 3/11, 2022 at 2:9 Comment(0)
H
1

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;
Hardcastle answered 14/11, 2018 at 15:14 Comment(0)
W
0

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>
    )
}
Walloper answered 22/9, 2021 at 8:35 Comment(0)
B
0
const fileInputRef = useRef(null);

const handleReset = () => {
    // Reset the file input by setting its value to an empty string
    fileInputRef.current.value = '';
};

<input type="file" ref={fileInputRef} />
<button onClick={handleReset}>Reset File Input</button>

The useRef hook is used to create a ref (fileInputRef) that will hold a reference to the file input element.

The handleReset function is called when the "Reset File Input" button is clicked. Inside this function, we directly access the value property of the file input through the fileInputRef and set it to an empty string, effectively resetting the file input.

Bespatter answered 5/2 at 10:49 Comment(0)
T
0

By just event.target.value = ''; make input:file unselect the file

Thanks

Transilient answered 21/3 at 5:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.