简体   繁体   中英

input's event.target is null within this.setState [React.js]

In my react component I have a file input:

<input type="file" onChange={this.onFileChange.bind(this)} />` 

and my onFileChange is:

onFileChange(e) {
  let file = e.target.files[0];
  this.setState(() => ({ file: e.target.files[0] })); //doesnt work
  // this.setState(() => ({ file })); //works
  // this.setState({ file: e.target.files[0] }); //works
}

This first way of setting the states fails with an error:

Cannot read property 'files' of null

React also gives the following warning:

This synthetic event is reused for performance reasons. If you're 
seeing this, you're accessing the property 'target' on a 
released/nullified synthetic event

But the last two ways of setting the state give no errors or warnings. Why is this happening?

The setState function is executed in asynchronous context.

By the time the state is updated the e.target reference might or might not be gone.

const file = e.target.files[0]; can be used to "remember" the value as in your example.

What is the reason for calling setState with callback ? this.setState({ file: e.target.files[0] }) should do the job.

In your code you are referring to a synthetic event object which no longer holds information about the original DOM event. React reuses the event objects for performance reasons.

Alternatively you can use:

let file = e.target.files[0]; const files = e.target.files this.setState(() => ({ file: files[0] })); //doesnt work

React uses event pooling, you can read more about it in the docs here https://reactjs.org/docs/events.html

setState is an asynchronous function

this.setState(() => ({ file })); // is correct

Very simple/basic example to do the same task:

class Hello extends React.Component {
    constructor(props) {
    super(props);
    this.state = {
    file: ''
    };
  }

  render() {
    return <div>
    <input type='file' onChange={(e) => {
    this.setState({file: e.target.files[0]}, () => {
        console.log('state', this.state);
    })
    }} />
    </div>;
  }
}

ReactDOM.render(
  <Hello name="World" />,
  document.getElementById('container')
);

I have added console log when the state will be set it will log the file details. You can see in the log when you select a file the state includes the file data.

To see the console log you need to right click and inspect and see the Console.

Checkout working example here https://jsfiddle.net/1oj3h417/2/

Let me know if you have any doubt

 class Example extends React.Component { onFileChange = e => { let file = e.target.files[0]; this.setState(() => ({ file: file })); } render() { return <input type="file" onChange={this.onFileChange} />; } } ReactDOM.render( <Example />, document.getElementById('root') );
 <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="root"> </div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM