Current Behavior:
I have a textinput box that has an onChange which takes a function as a prop (which sets state in a parent component). onChange is not registering an initial copy and paste. Oddly, when I type an extra key after what I pasted, it returns the string .length count of the original paste and _not_ the count with the additional character. It appears that React is one change behind, despite registering that something changed.
To make this more clear, I added some console.logs to see the behavior and found this:
setAccountKey()) but, despite explicitly setting state, it's not setting it. The key I'm pasting is 72 characters (verified by irb), but this.state.accountKey.length is displaying as 0.this.state.accountKey.length as 72 and this.state.accountKey as the original pasted key.Here's the abridged code:
import React, { Component, PropTypes } from 'react';
import Router from 'react-router';
import AuthForm from '../components/AuthForm';
import KeyEntry from '../components/KeyEntry';
export default class AuthorizationContainer extends Component {
constructor(props, context) {
super(props, context);
this.state = {
accountKey: '',
};
this.setAccountKey = this.setAccountKey.bind(this);
this.keyLengthValid = this.keyLengthValid.bind(this);
}
setAccountKey(event) {
let text = event.target.value;
this.setState({ accountKey: text });
console.log('I got here!');
// 'I got here' did display on initial paste
this.keyLengthValid();
console.log(this.state.accountKey);
console.log(this.keyLengthValid());
console.log(this.state.accountKey.length);
}
keyLengthValid() {
return this.state.accountKey.length === 72;
}
render() {
return (
<AuthForm onSubmitKey={ this.handleSubmitKey }>
<KeyEntry setAccountKey={ this.setAccountKey } />
</AuthForm>
);
}
};
AuthorizationContainer.contextTypes = {
router: PropTypes.object.isRequired,
};
////////////////////////
import React, { PropTypes, Component } from 'react';
export default class KeyEntry extends Component {
constructor(props) {
super(props);
}
render () {
return (
<textarea onChange={this.props.setAccountKey} placeholder="Please enter a valid API key." />
);
}
};
KeyEntry.propTypes = {
setAccountKey: PropTypes.func.isRequired,
};
Expected behavior:
On paste, accountKey state would be the key pasted and have a length of 72.
Versions Tested:
React version: 15.4.1
Chrome version: 54.0.2840.98
Similar issue: #7211
I haven鈥檛 looked in depth yet but if you expect this.state to be updated immediately after a setState call, that is not the case.
From the documentation:
setState()does not immediately mutatethis.statebut creates a pending state transition. Accessingthis.stateafter calling this method can potentially return the existing value.
There is no guarantee of synchronous operation of calls to
setStateand calls may be batched for performance gains.
Thanks! I didn't realize that was the behavior. I'm going to try with a callback and see if I'm still having the issue.
OK! The callback worked with paste immediately! My bad on that. I wrote such a pretty bug report for nothing 馃槈
Thanks for the help @gaearon :)
Not for nothing, it helped me respond quickly!
Most helpful comment
I haven鈥檛 looked in depth yet but if you expect
this.stateto be updated immediately after asetStatecall, that is not the case.From the documentation: