Skip to content

Commit

Permalink
CheckBox: Convert NativeMethodsMixin to forwardedRef, convert to class (
Browse files Browse the repository at this point in the history
#21585)

Summary:
This PR converts the use of `NativeMethodsMixin` in `CheckBox.android.js`, and converts it to an ES6-style class.
Pull Request resolved: #21585

Reviewed By: TheSavior

Differential Revision: D12827768

Pulled By: RSNara

fbshipit-source-id: c113c221335e61e015a20bbb6bcff5f9837f9022
  • Loading branch information
empyrical authored and facebook-github-bot committed Nov 2, 2018
1 parent 14e1628 commit 28de61e
Showing 1 changed file with 105 additions and 71 deletions.
176 changes: 105 additions & 71 deletions Libraries/Components/CheckBox/CheckBox.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down Expand Up @@ -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);

0 comments on commit 28de61e

Please sign in to comment.