5
votes

Using React v16.1, on a local development server. I have a simple component to upload a file here:

class FileImporter extends React.Component {
    constructor(props) {...}
    importFile(e) {
      // import the file here, not firing
    }
    render() {
      return (<input type="file" onChange={this.importFile.bind(this)} />);
    }
}    

The function importFile never fires. I've tried binding onChange in the following ways:

onChange={e => this.importFile(e)}
onChange={this.importFile.bind(this)}
onChange={this.importFile}

I've tried using react-file-reader-input and react-file-reader, and just a raw input tag like in the snippet. None of them fire the onChange handler. The system file upload dialog shows up, but on selecting a file nothing happens. How can I get the onChange event to fire?

7

7 Answers

19
votes

For others who google here: I had a similar issue and the solution I found was that my <input> was being removed from the DOM after clicking the button to open the file picker. (It was inside a drop down.)

Clicking the input still showed the file picker, but that also caused the drop down to hide, thus removing the input from the DOM. After selecting a file the onChange never fired. I moved the input to a place that it wouldn't be removed from the DOM and things began to work again.

4
votes

I have experienced the same issue. The problem was that I have the same id for the multiple inputs. Once I set a unique id for each input problem was solved. Thanks

<label htmlFor="file-input-id">Upload</label>
<input type="file" id="file-input-id" onChange={this.onSelectImage} />
1
votes

It works here:

class FileImporter extends React.Component {    
    importFile(e) {
      console.log("fired.");
    }
    render() {
      return (<input type="file" onChange={this.importFile.bind(this)} />);
    }
}

ReactDOM.render(<FileImporter />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="app"></div>

So it must be something else you're doing or some other code. I know this is a different version of React, but it should work the same for you.

0
votes

It's by design in Chrome. Set value to empty string and store the file in useState() hook or ref.

0
votes

Use onInput instead of onChange

                <div className="profile-form-buttons centercontents">
                    <input className="form-compo"
                        type="file" 
                        name="file-uploader" 
                        id="file-uploader"  
                        onInput={imageUpdate}
                        style={{display:"none"}}
                        />
                </div>
0
votes

For functional component, we can use onInputCapture or onChangeCapture.

There is not documentation on React but we can track on this Issue - Diff b/w onChange and onInput and StackOverflow - Difference between onChange and onInput. All the examples are about onInput not onInputCapture.

Finally, able to get TS definition onInputCapture and onChangeCapture, React TS.

    onChange?: FormEventHandler<T> | undefined;
    onChangeCapture?: FormEventHandler<T> | undefined;
    onInput?: FormEventHandler<T> | undefined;
    onInputCapture?: FormEventHandler<T> | undefined;

MDN Docs - GlobalEventHandlers.oninput

const FileSelector = () => (
    <input
        type="file"
        onInputCapture={(e) => console.log(e.target)}
        accept={".xlsx"}
        multiple={false}
    />
);
-5
votes
constructor(props) {
    super(props);
    this.state = {
        value: ''
    }
}
render(){
    return(
       <input type="text" 
              value={this.state.value} 
              onChange={(e) => this.setState({value: e.target.value})}/>
    )
}