Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Event target is null inside functional setState

Consider below function of some component:

handleInputChange(e) {     // let val = e.target.value; - if I uncomment this, it works.      // Update text box value     this.setState(function (prevState, props) {         return {           searchValue: e.target.value,         }     }) } 

and a textbox, which is rendered by a child component of above component, and receives handleInputChange as props:

<input type="text" onChange={that.props.handleInputChange} value={that.props.searchValue} /> 

When I enter something in text field I get error that Cannot read property 'value' of null.

If I uncomment the first line inside handleInputChange function, where I store text box value inside val variable, it works well. Ideas why?

like image 568
Giorgi Moniava Avatar asked Jun 22 '17 20:06

Giorgi Moniava


1 Answers

That is because react before version 17 was doing event pooling - all the event's fields get nullified after the callback is done, so you observe them as nulls in the asynchronous setState callback.

Please copy your event data to a variable or call event.persist() to disable this behavior.

handleInputChange(e) {   e.persist();    this.setState(function (prevState, props) {       return {         searchValue: e.target.value,       }   }) } 

Or:

handleInputChange(e) {   const val = e.target.value;    this.setState(function (prevState, props) {       return {         searchValue: val       }   }) } 

Please see the following example:

class Example extends React.Component {   constructor() {     super()     this.state = { }   }      handleInputChangeCopy = (e) => {        const val = e.target.value;          console.log('in callback');     console.log(e.target.value);          this.setState(function (prevState, props) {         console.log('in async callback');         console.log(val);                  return {           searchValue: val         }     })   }      handleInputChangePersist = (e) => {     e.persist();     console.log('in callback');     console.log(e.target.value);          this.setState(function (prevState, props) {         console.log('in async callback');         console.log({ isNull: e.target === null })                  console.log(e.target.value);                  return {           searchValue: e.target.value         }     })   }      handleInputChange = (e) => {     console.log('in callback');     console.log(e.target.value);          this.setState(function (prevState, props) {         console.log('in async callback');                  console.log({ isNull: e.target === null })         console.log({ event: e });                  console.log(e.target.value);                  return {             searchValue: e.target.value         }     })   }      render() {     return (     <div>       <div>Copy example</div>       <input          type="text"         onChange={this.handleInputChangeCopy}        />              <p>Persist example</p>       <input          type="text"         onChange={this.handleInputChangePersist}        />              <p>Original example - please note nullified fields of the event in the async callback. <small>Breaks the example, please re-run after a Script error</small></p>       <input          type="text"         onChange={this.handleInputChange}        />        <div style={{height: 300}} />     </div>     )   } }  ReactDOM.render(   <Example searchValue={"test"} />,   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>
like image 112
Przemysław Zalewski Avatar answered Sep 30 '22 15:09

Przemysław Zalewski