CheckBox: Convert NativeMethodsMixin to forwardedRef, convert to class (#21585)

Summary:
This PR converts the use of `NativeMethodsMixin` in `CheckBox.android.js`, and converts it to an ES6-style class.
Pull Request resolved: https://github.com/facebook/react-native/pull/21585

Reviewed By: TheSavior

Differential Revision: D12827768

Pulled By: RSNara

fbshipit-source-id: c113c221335e61e015a20bbb6bcff5f9837f9022
This commit is contained in:
empyrical 2018-11-02 10:29:47 -07:00 committed by Facebook Github Bot
parent 14e1628ba8
commit 28de61e9f0
1 changed files with 105 additions and 71 deletions

View File

@ -9,21 +9,76 @@
*/
'use strict';
const DeprecatedViewPropTypes = require('DeprecatedViewPropTypes');
const NativeMethodsMixin = require('NativeMethodsMixin');
const PropTypes = require('prop-types');
const React = require('React');
const StyleSheet = require('StyleSheet');
const createReactClass = require('create-react-class');
const requireNativeComponent = require('requireNativeComponent');
const nullthrows = require('nullthrows');
const setAndForwardRef = require('setAndForwardRef');
const RCTCheckBox = requireNativeComponent('AndroidCheckBox');
import type {ViewProps} from 'ViewPropTypes';
import type {SyntheticEvent} from 'CoreEventTypes';
import type {NativeComponent} from 'ReactNative';
type DefaultProps = {
value: boolean,
disabled: boolean,
};
type CheckBoxEvent = SyntheticEvent<
$ReadOnly<{|
target: number,
value: boolean,
|}>,
>;
type CommonProps = $ReadOnly<{|
...ViewProps,
/**
* Used in case the props change removes the component.
*/
onChange?: ?(event: CheckBoxEvent) => mixed,
/**
* Invoked with the new value when the value changes.
*/
onValueChange?: ?(value: boolean) => mixed,
/**
* Used to locate this view in end-to-end tests.
*/
testID?: ?string,
|}>;
type NativeProps = $ReadOnly<{|
...CommonProps,
on?: ?boolean,
enabled?: boolean,
|}>;
type CheckBoxNativeType = Class<NativeComponent<NativeProps>>;
type Props = $ReadOnly<{|
...CommonProps,
/**
* The value of the checkbox. If true the checkbox will be turned on.
* Default value is false.
*/
value?: ?boolean,
/**
* If true the user won't be able to toggle the checkbox.
* Default value is false.
*/
disabled?: ?boolean,
/**
* Used to get the ref for the native checkbox
*/
forwardedRef?: ?React.Ref<CheckBoxNativeType>,
|}>;
const RCTCheckBox = ((requireNativeComponent(
'AndroidCheckBox',
): any): CheckBoxNativeType);
/**
* Renders a boolean input (Android only).
@ -80,85 +135,64 @@ type DefaultProps = {
* @keyword checkbox
* @keyword toggle
*/
let CheckBox = createReactClass({
displayName: 'CheckBox',
propTypes: {
...DeprecatedViewPropTypes,
/**
* The value of the checkbox. If true the checkbox will be turned on.
* Default value is false.
*/
value: PropTypes.bool,
/**
* If true the user won't be able to toggle the checkbox.
* Default value is false.
*/
disabled: PropTypes.bool,
/**
* Used in case the props change removes the component.
*/
onChange: PropTypes.func,
/**
* Invoked with the new value when the value changes.
*/
onValueChange: PropTypes.func,
/**
* Used to locate this view in end-to-end tests.
*/
testID: PropTypes.string,
},
class CheckBox extends React.Component<Props> {
_nativeRef: ?React.ElementRef<CheckBoxNativeType> = null;
_setNativeRef = setAndForwardRef({
getForwardedRef: () => this.props.forwardedRef,
setLocalRef: ref => {
this._nativeRef = ref;
},
});
getDefaultProps: function(): DefaultProps {
return {
value: false,
disabled: false,
};
},
mixins: [NativeMethodsMixin],
_rctCheckBox: {},
_onChange: function(event: Object) {
this._rctCheckBox.setNativeProps({value: this.props.value});
_onChange = (event: CheckBoxEvent) => {
const value = this.props.value ?? false;
nullthrows(this._nativeRef).setNativeProps({value: value});
// Change the props after the native props are set in case the props
// change removes the component
this.props.onChange && this.props.onChange(event);
this.props.onValueChange &&
this.props.onValueChange(event.nativeEvent.value);
},
};
render: function() {
let props = {...this.props};
props.onStartShouldSetResponder = () => true;
props.onResponderTerminationRequest = () => false;
/* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
* when making Flow check .android.js files. */
props.enabled = !this.props.disabled;
/* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
* when making Flow check .android.js files. */
props.on = this.props.value;
props.style = [styles.rctCheckBox, this.props.style];
render() {
const {disabled: _, value: __, style, forwardedRef, ...props} = this.props;
const disabled = this.props.disabled ?? false;
const value = this.props.value ?? false;
const nativeProps = {
...props,
onStartShouldSetResponder: () => true,
onResponderTerminationRequest: () => false,
enabled: !disabled,
on: value,
style: [styles.rctCheckBox, style],
};
return (
<RCTCheckBox
{...props}
ref={ref => {
/* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This
* comment suppresses an error when upgrading Flow's support for
* React. To see the error delete this comment and run Flow. */
this._rctCheckBox = ref;
}}
{...nativeProps}
ref={this._setNativeRef}
onChange={this._onChange}
/>
);
},
});
}
}
let styles = StyleSheet.create({
const styles = StyleSheet.create({
rctCheckBox: {
height: 32,
width: 32,
},
});
module.exports = CheckBox;
/**
* Can't use CheckBoxNativeType because it has different props
*/
type CheckBoxType = Class<NativeComponent<Props>>;
// $FlowFixMe - TODO T29156721 `React.forwardRef` is not defined in Flow, yet.
const CheckBoxWithRef = React.forwardRef(function CheckBoxWithRef(props, ref) {
return <CheckBox {...props} forwardedRef={ref} />;
});
module.exports = (CheckBoxWithRef: CheckBoxType);