How to reset ReactJS file input
HtmlReactjsFile UploadHtml 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 (
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:
- Returns a stateful value, and a function to update it.
- If you pass a ref object to React, React will set its current property to the corresponding DOM node whenever that node changes.
-
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>
)
}