Issue of using e.target.value in React setState function

I am experiencing a strange issue in React. I think probably I have not fully grasped how React works and I really appreciate your help.

Please find below my React component:

class myComponent extends Component {
  state = {
    value: ''
  }

  updateValue = e => {
    this.setState({
      value: e.target.value
    })
  }

  render() {
    return (
     <form>
      <input type="text" onChange={this.updateValue} defaultValue={this.state.value} />
     </form>
    )
  }
}

Then, now if I type something in the text field, I will get following warning and errors:

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. This is set to null. If you must keep the original synthetic event around, use event.persist().

Uncaught TypeError: Cannot read property ‘value’ of null

But if I change the ‘updateValue’ method to:

updateValue = e => {
    const newValue = e.target.value
    this.setState({
      value: newValue
    })
  }

It will work without any issue.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

Updated answer

As @FelixKling pointed out, my answer wasn’t entirely correct. My answer is only valid if you pass a function as a parameter to setState, not if you pass an object like done in the question.

If you pass an object to setState, the parameter will be evaluated immediately, that is, before the event has been nullified. As such, the mentioned error won’t occur.

If you pass a function to setState, the parameter will be evaluated within that function, which happens after updateValue has completed/returned and the event has been nullified. If you pass a function to setState, you must store the e.target.value in a variable (or call e.persist()) before setState.

Old (slightly wrong) answer

This problem occurs because (as the error message says) the event is set to null when the callback (your updateValue function) is completed.

Because this.setState() is an asynchronous function, it will not be executed immediately. As a result, this.setState() is actually executed after your updateValue is finished, and hence after the event has been nullified.

Your solution is actually the proposed way from the React docs!

Method 2

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.

Basically, the click event (e) is not accessible inside the asynchronous setState() due to React’s Event Pooling, unless you use event.persist() (as mentioned in the warning you received).

React Event Pooling: https://reactjs.org/docs/events.html

Method 3

If someone is looking for the way to make work this. Here a snipped.

class myComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      value: ''
    };
    this.updateValue = this.updateValue.bind(this);
  }
  updateValue(e) {
    this.setState({ value: e.target.value })
  }
  render() {
    return ( <form>
      <input type="text" value={this.state.value} 
        onChange={this.updateValue} 
        defaultValue={this.state.value} />
      <h4>Controlled Input:</h4> <p>{this.state.value}</p>
      </form>
    ); 
  }
};

Method 4

On functional components

const [name, setName] = useState('');

<input onChange={(e) => setName(e.target.value)} />


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x