How to allow input type=file to select the same file in react component
JavascriptReactjsJavascript Problem Overview
I have a react component which renders a <input type="file">
dom to allow user select images from browser. I found that its onChange method not called when I select the same file. After some searching, someone suggests using this.value=null
or return false
at the end of the onChange method but I have tried it doesn't work.
Below is my code:
<input id="upload" ref="upload" type="file" accept="image/*"
onChange={(event)=> { this.readFile(event) }}/>
Below is what I tried:
<input id="upload" ref="upload" type="file" accept="image/*"
onChange={(event)=> {
this.readFile(event)
return false
}}/>
Another one is:
<input id="upload" ref="upload" type="file" accept="image/*"
onChange={(event)=> {
this.readFile(event)
this.value=null
}}/>
I believe above solutions work for jquery but I don't know how to let it work in reactjs.
Javascript Solutions
Solution 1 - Javascript
Dup of this thread
<input id="upload" ref="upload" type="file" accept="image/*"
onChange={(event)=> {
this.readFile(event)
}}
onClick={(event)=> {
event.target.value = null
}}
/>
Solution 2 - Javascript
I think this
in your function does not refer to input
field. Try using event.target
instead.
<input id="upload" ref="upload" type="file" accept="image/*"
onChange={(event)=> {
this.readFile(event)
event.target.value=null
}}/>
Solution 3 - Javascript
For me actually worked: event.currentTarget.value = null
onClick={(event)=> {
event.currentTarget.value = null
}}
Solution 4 - Javascript
My React version: 16.2.0
@jbsmoove solution works fine for all browsers except IE11.
As for IE11, in case if we Open some file and in second time we press Cancel insteed of Open file it shows empty screen and in console we see:
> Unable to get property 'name' of undefined or null reference
So I've come up with another solution which works perfect even in IE11:
<input id="upload" ref="upload" type="file" accept="image/*"
onInput={(event)=> {
this.readFile(event)
}}
onClick={(event)=> {
event.target.value = null
}}
/>
Just use onInput instead of onChange.
Solution 5 - Javascript
Below is my solution. (Using Typescript)
import * as React from "react";
export class FileSelector extends React.Component<undefined, undefined>
{
constructor(props: any)
{
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(selectorFiles: FileList)
{
console.log(selectorFiles);
}
render ()
{
return <div>
<input type="file" onChange={ (e) => this.handleChange(e.target.files) } />
</div>;
}
}
Solution 6 - Javascript
Use a fallback on-Click method to select the same image. Example:
<input
id="upload"
ref="upload"
type="file"
accept="image/*"
multiple="false"
onChange={(e) => this.getDailyImage(e)}
onClick={(e) => e.target.files[0] && this.getDailyImage(e)}
/>
Solution 7 - Javascript
I usually just use key
prop on input to reset it's underlying DOM node between selections (either use some incremental UID counter in change handler or uploading/processing state flag):
const UploadInput = (props) => {
const [isUploading, setUploading] = useState(false);
const handleChange = useCallback((async (e) => {
setUploading(true); // or setUID((old) => old + 1);
try {
await ... // handle processing here
} finally {
setUploading(false);
}
}, [...]);
return (
<div className={...}>
<input key={isUploading} type="file" onChange={handleChange} {...props} />
{isUploading && <Spinner />}
</div>
);
};
Another way might be to get ref
of the form and use formRef.reset()
after processing (viable if you don't care for form contents after file processing).
Solution 8 - Javascript
I got mine to work by adding the following onchange
event listener in my input
, using Typescript.
const onInputFileChange = (
event: ChangeEvent<HTMLInputElement>
): void => {
const nativeEvent = event.nativeEvent.target as HTMLInputElement;
const targetEvent = event.target as HTMLInputElement;
if (targetEvent.files && targetEvent.files[0]) {
const imageFile = targetEvent.files[0];
// eslint-disable-next-line no-param-reassign
nativeEvent.value = "";
}
};