Skip to content

Commit

Permalink
Convert TextInput from NativeMethodsMixin to ES6 Class
Browse files Browse the repository at this point in the history
Summary:
In order to make this more flow typed and modern we need to get it off of createReactClass. This change converts the class as is with no intended behavior changes to an ES6 class.

Changelog: [Internal]

Reviewed By: JoshuaGross

Differential Revision: D18443018

fbshipit-source-id: 831921976e9de8e965180cdefd1c4a154f04bfea
  • Loading branch information
elicwhite authored and facebook-github-bot committed Nov 15, 2019
1 parent ce314ba commit 8f60141
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 73 deletions.
141 changes: 69 additions & 72 deletions Libraries/Components/TextInput/TextInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ const TextAncestor = require('../../Text/TextAncestor');
const TextInputState = require('./TextInputState');
const TouchableWithoutFeedback = require('../Touchable/TouchableWithoutFeedback');

const createReactClass = require('create-react-class');
const invariant = require('invariant');
const requireNativeComponent = require('../../ReactNative/requireNativeComponent');

Expand Down Expand Up @@ -792,32 +791,28 @@ const emptyFunctionThatReturnsTrue = () => true;
* or control this param programmatically with native code.
*
*/

const TextInput = createReactClass({
displayName: 'TextInput',
statics: {
State: {
currentlyFocusedField: TextInputState.currentlyFocusedField,
focusTextInput: TextInputState.focusTextInput,
blurTextInput: TextInputState.blurTextInput,
},
},
propTypes: DeprecatedTextInputPropTypes,
getDefaultProps() {
return {
allowFontScaling: true,
rejectResponderTermination: true,
underlineColorAndroid: 'transparent',
};
},

_inputRef: (undefined: any),
_focusSubscription: (undefined: ?Function),
_lastNativeText: (undefined: ?string),
_lastNativeSelection: (undefined: ?Selection),
_rafId: (null: ?AnimationFrameID),

componentDidMount: function() {
class TextInput extends React.Component<Props> {
static defaultProps = {
allowFontScaling: true,
rejectResponderTermination: true,
underlineColorAndroid: 'transparent',
};

static propTypes = DeprecatedTextInputPropTypes;

static State = {
currentlyFocusedField: TextInputState.currentlyFocusedField,
focusTextInput: TextInputState.focusTextInput,
blurTextInput: TextInputState.blurTextInput,
};

_inputRef: ?React.ElementRef<HostComponent<mixed>> = null;
_focusSubscription: ?Function = undefined;
_lastNativeText: ?Stringish = null;
_lastNativeSelection: ?Selection = null;
_rafId: ?AnimationFrameID = null;

componentDidMount() {
this._lastNativeText = this.props.value;
const tag = ReactNative.findNodeHandle(this._inputRef);
if (tag != null) {
Expand All @@ -828,9 +823,9 @@ const TextInput = createReactClass({
if (this.props.autoFocus) {
this._rafId = requestAnimationFrame(this.focus);
}
},
}

componentDidUpdate: function() {
componentDidUpdate() {
// 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.
Expand Down Expand Up @@ -862,9 +857,9 @@ const TextInput = createReactClass({
) {
this._inputRef.setNativeProps(nativeProps);
}
},
}

componentWillUnmount: function() {
componentWillUnmount() {
this._focusSubscription && this._focusSubscription.remove();
if (this.isFocused()) {
this.blur();
Expand All @@ -876,57 +871,57 @@ const TextInput = createReactClass({
if (this._rafId != null) {
cancelAnimationFrame(this._rafId);
}
},
}

/**
* Removes all text from the `TextInput`.
*/
clear: function() {
clear = () => {
this.setNativeProps({text: ''});
},
};

/**
* Returns `true` if the input is currently focused; `false` otherwise.
*/
isFocused: function(): boolean {
isFocused = (): boolean => {
return (
TextInputState.currentlyFocusedField() ===
ReactNative.findNodeHandle(this._inputRef)
);
},
};

getNativeRef: function(): ?React.ElementRef<HostComponent<mixed>> {
getNativeRef = (): ?React.ElementRef<HostComponent<mixed>> => {
return this._inputRef;
},
};

// From NativeMethodsMixin
// We need these instead of using forwardRef because we also have the other
// methods we expose
blur: function() {
blur = () => {
this._inputRef && this._inputRef.blur();
},
focus: function() {
};
focus = () => {
this._inputRef && this._inputRef.focus();
},
measure: function(callback: MeasureOnSuccessCallback) {
};
measure = (callback: MeasureOnSuccessCallback) => {
this._inputRef && this._inputRef.measure(callback);
},
measureInWindow: function(callback: MeasureInWindowOnSuccessCallback) {
};
measureInWindow = (callback: MeasureInWindowOnSuccessCallback) => {
this._inputRef && this._inputRef.measureInWindow(callback);
},
measureLayout: function(
};
measureLayout = (
relativeToNativeNode: number | React.ElementRef<HostComponent<mixed>>,
onSuccess: MeasureLayoutOnSuccessCallback,
onFail?: () => void,
) {
) => {
this._inputRef &&
this._inputRef.measureLayout(relativeToNativeNode, onSuccess, onFail);
},
setNativeProps: function(nativeProps: Object) {
};
setNativeProps = (nativeProps: Object) => {
this._inputRef && this._inputRef.setNativeProps(nativeProps);
},
};

render: function() {
render() {
let textInput = null;
let additionalTouchableProps: {|
rejectResponderTermination?: $PropertyType<
Expand Down Expand Up @@ -988,6 +983,8 @@ const TextInput = createReactClass({
}

textInput = (
/* $FlowFixMe the types for AndroidTextInput don't match up exactly with
the props for TextInput. This will need to get fixed */
<AndroidTextInput
ref={this._setNativeRef}
{...this.props}
Expand Down Expand Up @@ -1024,27 +1021,27 @@ const TextInput = createReactClass({
</TouchableWithoutFeedback>
</TextAncestor.Provider>
);
},
}

_getText: function(): ?string {
_getText(): ?string {
return typeof this.props.value === 'string'
? this.props.value
: typeof this.props.defaultValue === 'string'
? this.props.defaultValue
: '';
},
}

_setNativeRef: function(ref: any) {
_setNativeRef = (ref: any) => {
this._inputRef = ref;
},
};

_onPress: function(event: PressEvent) {
_onPress = (event: PressEvent) => {
if (this.props.editable || this.props.editable === undefined) {
this.focus();
}
},
};

_onChange: function(event: ChangeEvent) {
_onChange = (event: ChangeEvent) => {
// Make sure to fire the mostRecentEventCount first so it is already set on
// native when the text value is set.
if (this._inputRef && this._inputRef.setNativeProps) {
Expand All @@ -1065,9 +1062,9 @@ const TextInput = createReactClass({

this._lastNativeText = text;
this.forceUpdate();
},
};

_onSelectionChange: function(event: SelectionChangeEvent) {
_onSelectionChange = (event: SelectionChangeEvent) => {
this.props.onSelectionChange && this.props.onSelectionChange(event);

if (!this._inputRef) {
Expand All @@ -1081,30 +1078,30 @@ const TextInput = createReactClass({
if (this.props.selection) {
this.forceUpdate();
}
},
};

_onFocus: function(event: FocusEvent) {
_onFocus = (event: FocusEvent) => {
TextInputState.focusField(ReactNative.findNodeHandle(this._inputRef));
if (this.props.onFocus) {
this.props.onFocus(event);
}
},
};

_onBlur: function(event: BlurEvent) {
_onBlur = (event: BlurEvent) => {
TextInputState.blurField(ReactNative.findNodeHandle(this._inputRef));
if (this.props.onBlur) {
this.props.onBlur(event);
}
},
};

_onTextInput: function(event: TextInputEvent) {
_onTextInput = (event: TextInputEvent) => {
this.props.onTextInput && this.props.onTextInput(event);
},
};

_onScroll: function(event: ScrollEvent) {
_onScroll = (event: ScrollEvent) => {
this.props.onScroll && this.props.onScroll(event);
},
});
};
}

class InternalTextInputType extends ReactNative.NativeComponent<Props> {
clear() {}
Expand Down
3 changes: 2 additions & 1 deletion Libraries/Utilities/ReactNativeTestTools.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ function byTextMatching(regex: RegExp): Predicate {

function enter(instance: ReactTestInstance, text: string) {
const input = instance.findByType(TextInput);
input.instance._onChange({nativeEvent: {text}});
input.props.onChange && input.props.onChange({nativeEvent: {text}});
input.props.onChangeText && input.props.onChangeText(text);
}

// Returns null if there is no error, otherwise returns an error message string.
Expand Down

0 comments on commit 8f60141

Please sign in to comment.