React: Inconsistent setState behavior while using controlled components

Created on 26 Nov 2018  路  3Comments  路  Source: facebook/react

Do you want to request a feature or report a bug?
I want to report a bug.

What is the current behavior?
While using an input as controlled component:

<input
  type="input"
  value={this.state.inputValue}
  onChange={this.handleChange}
/>

writing

 handleChange = e => {
   this.setState({ inputValue: e.target.value });
 };

works well but using functional setState

 handleChange = e => {
   this.setState(() => ({ inputValue: e.target.value }));
 };

crashes with TypeError: Cannot read property 'value' of null

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem. Your bug will get fixed much faster if we can run your code and it doesn't have dependencies other than React. Paste the link to your JSFiddle (https://jsfiddle.net/Luktwrdm/) or CodeSandbox (https://codesandbox.io/s/new) example below:

Working example:
https://jsfiddle.net/Luktwrdm/1435/

Crashing example (using functional setState)
https://jsfiddle.net/Luktwrdm/1436/

Demo:
reactbug

What is the expected behavior?
The expected behavior is that both setState (with object and with function) should have the same behavior for end-users.

Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?
Browser: Google Chrome Version 70.0.3538.102 (Official Build) (64-bit)
React Version: 16.6.1

Most helpful comment

right below that para is the solution -

Note:

If you want to access the event properties in an asynchronous way, you should 
call event.persist() on the event, which will remove the synthetic event from the 
pool and allow references to the event to be retained by user code.

this fixes the crash -

  handleChange = e => {
    e.persist()
    this.setState(() => ({ value: e.target.value }));
  }

All 3 comments

From https://reactjs.org/docs/events.html#event-pooling

The SyntheticEvent is pooled.
This means that the SyntheticEvent object will be reused and all properties
will be nullified after the event callback has been invoked.
This is for performance reasons. As such, you cannot access the event in
an asynchronous way.

Is there a way to access events asynchronously ? 馃槆Isn't setState async ?

right below that para is the solution -

Note:

If you want to access the event properties in an asynchronous way, you should 
call event.persist() on the event, which will remove the synthetic event from the 
pool and allow references to the event to be retained by user code.

this fixes the crash -

  handleChange = e => {
    e.persist()
    this.setState(() => ({ value: e.target.value }));
  }

@threepointone Thanks ! 馃槉

Was this page helpful?
0 / 5 - 0 ratings