Fixed controlled component on iOS and remove unnecessary code

Summary:
Closes #4290

`mostRecentEventCount` was always being set after `text` on iOS, so let's be really explicit about the order here as we were doing on Android: always call `setNativeProps` providing the `mostRecentEventCount` before we call `onChange` or `onChangeText`.

I also ripped out storing `mostRecentEventCount` in the state, which isn't necessary since we're always doing it through `setNativeProps`.
Closes https://github.com/facebook/react-native/pull/4588

Reviewed By: svcscm

Differential Revision: D2754565

Pulled By: nicklockwood

fb-gh-sync-id: a1401f39b4e19248095517c2a3503cd2af59fa47
This commit is contained in:
Brent Vatne 2015-12-14 06:41:45 -08:00 committed by facebook-github-bot-0
parent 2f56c0c90a
commit c8108bdbe1
2 changed files with 43 additions and 29 deletions

View File

@ -125,6 +125,27 @@ class RewriteExample extends React.Component {
}
}
class RewriteExampleInvalidCharacters extends React.Component {
constructor(props) {
super(props);
this.state = {text: ''};
}
render() {
return (
<View style={styles.rewriteContainer}>
<TextInput
multiline={false}
onChangeText={(text) => {
this.setState({text: text.replace(/\s/g, '')});
}}
style={styles.default}
value={this.state.text}
/>
</View>
);
}
}
class TokenizedTextExample extends React.Component {
constructor(props) {
super(props);
@ -313,6 +334,12 @@ exports.examples = [
return <RewriteExample />;
}
},
{
title: "Live Re-Write (no spaces allowed)",
render: function() {
return <RewriteExampleInvalidCharacters />;
}
},
{
title: 'Auto-capitalize',
render: function() {

View File

@ -329,12 +329,6 @@ var TextInput = React.createClass({
React.findNodeHandle(this.refs.input);
},
getInitialState: function() {
return {
mostRecentEventCount: 0,
};
},
contextTypes: {
onFocusRequested: React.PropTypes.func,
focusEmitter: React.PropTypes.instanceOf(EventEmitter),
@ -431,7 +425,6 @@ var TextInput = React.createClass({
onSelectionChange={onSelectionChange}
onSelectionChangeShouldSetResponder={emptyFunction.thatReturnsTrue}
text={this._getText()}
mostRecentEventCount={this.state.mostRecentEventCount}
/>;
} else {
for (var propKey in notMultiline) {
@ -460,7 +453,6 @@ var TextInput = React.createClass({
ref="input"
{...props}
children={children}
mostRecentEventCount={this.state.mostRecentEventCount}
onFocus={this._onFocus}
onBlur={this._onBlur}
onChange={this._onChange}
@ -506,7 +498,7 @@ var TextInput = React.createClass({
textAlign={textAlign}
textAlignVertical={textAlignVertical}
keyboardType={this.props.keyboardType}
mostRecentEventCount={this.state.mostRecentEventCount}
mostRecentEventCount={0}
multiline={this.props.multiline}
numberOfLines={this.props.numberOfLines}
maxLength={this.props.maxLength}
@ -548,29 +540,24 @@ var TextInput = React.createClass({
},
_onChange: function(event: Event) {
if (Platform.OS === 'android') {
// Android expects the event count to be updated as soon as possible.
this.refs.input.setNativeProps({
mostRecentEventCount: event.nativeEvent.eventCount,
});
}
// Make sure to fire the mostRecentEventCount first so it is already set on
// native when the text value is set.
this.refs.input.setNativeProps({
mostRecentEventCount: event.nativeEvent.eventCount,
});
var text = event.nativeEvent.text;
var eventCount = event.nativeEvent.eventCount;
this.props.onChange && this.props.onChange(event);
this.props.onChangeText && this.props.onChangeText(text);
this.setState({mostRecentEventCount: eventCount}, () => {
// NOTE: this doesn't seem to be needed on iOS - keeping for now in case it's required on Android
if (Platform.OS === 'android') {
// This is a controlled component, so make sure to force the native value
// to match. Most usage shouldn't need this, but if it does this will be
// more correct but might flicker a bit and/or cause the cursor to jump.
if (text !== this.props.value && typeof this.props.value === 'string') {
this.refs.input.setNativeProps({
text: this.props.value,
});
}
}
});
// This is necessary in case native updates the text and JS decides
// that the update should be ignored and we should stick with the value
// that we have in JS.
if (text !== this.props.value && typeof this.props.value === 'string') {
this.refs.input.setNativeProps({
text: this.props.value,
});
}
},
_onBlur: function(event: Event) {