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?
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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With