From e1339bc18303ca5394cd0c9dc97cededb2261581 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Wed, 9 May 2018 00:47:46 -0700 Subject: [PATCH] RN: Replace `context.isInAParentText` w/ React.createContext Reviewed By: sahrens Differential Revision: D7895382 fbshipit-source-id: 4affcecd147b8e8c506e0d94f223bac3e6dfdf66 --- Libraries/Components/TextInput/TextInput.js | 21 ++--- Libraries/Components/View/View.js | 38 +++++----- Libraries/Image/Image.android.js | 76 +++++++++---------- Libraries/Text/Text.js | 29 ++++--- .../ViewContext.js => Text/TextAncestor.js} | 16 ++-- 5 files changed, 85 insertions(+), 95 deletions(-) rename Libraries/{Components/View/ViewContext.js => Text/TextAncestor.js} (53%) diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js index f0cf5b955e9612..754af17e1bcb56 100644 --- a/Libraries/Components/TextInput/TextInput.js +++ b/Libraries/Components/TextInput/TextInput.js @@ -20,6 +20,7 @@ const PropTypes = require('prop-types'); const ReactNative = require('ReactNative'); const StyleSheet = require('StyleSheet'); const Text = require('Text'); +const TextAncestor = require('TextAncestor'); const TextInputState = require('TextInputState'); /* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error * found when Flow v0.54 was deployed. To see the error delete this comment and @@ -28,7 +29,6 @@ const TimerMixin = require('react-timer-mixin'); const TouchableWithoutFeedback = require('TouchableWithoutFeedback'); const UIManager = require('UIManager'); const ViewPropTypes = require('ViewPropTypes'); -const {ViewContextTypes} = require('ViewContext'); const emptyFunction = require('fbjs/lib/emptyFunction'); const invariant = require('fbjs/lib/invariant'); @@ -47,8 +47,6 @@ const onlyMultiline = { children: true, }; -import type {ViewChildContext} from 'ViewContext'; - if (Platform.OS === 'android') { AndroidTextInput = requireNativeComponent('AndroidTextInput', null); } else if (Platform.OS === 'ios') { @@ -701,16 +699,7 @@ const TextInput = createReactClass({ } }, - getChildContext(): ViewChildContext { - return { - isInAParentText: true, - }; - }, - - childContextTypes: ViewContextTypes, - contextTypes: { - ...ViewContextTypes, onFocusRequested: PropTypes.func, focusEmitter: PropTypes.instanceOf(EventEmitter), }, @@ -723,13 +712,17 @@ const TextInput = createReactClass({ }, render: function() { + let textInput; if (Platform.OS === 'ios') { - return UIManager.RCTVirtualText + textInput = UIManager.RCTVirtualText ? this._renderIOS() : this._renderIOSLegacy(); } else if (Platform.OS === 'android') { - return this._renderAndroid(); + textInput = this._renderAndroid(); } + return ( + {textInput} + ); }, _getText: function(): ?string { diff --git a/Libraries/Components/View/View.js b/Libraries/Components/View/View.js index 558f40a5d4087c..1e79f88a5483d4 100644 --- a/Libraries/Components/View/View.js +++ b/Libraries/Components/View/View.js @@ -7,6 +7,7 @@ * @flow * @format */ + 'use strict'; const Platform = require('Platform'); @@ -14,13 +15,13 @@ const React = require('React'); const ReactNative = require('ReactNative'); const ReactNativeStyleAttributes = require('ReactNativeStyleAttributes'); const ReactNativeViewAttributes = require('ReactNativeViewAttributes'); +const TextAncestor = require('TextAncestor'); const ViewPropTypes = require('ViewPropTypes'); -const {ViewContextTypes} = require('ViewContext'); + const invariant = require('fbjs/lib/invariant'); const requireNativeComponent = require('requireNativeComponent'); import type {ViewProps} from 'ViewPropTypes'; -import type {ViewChildContext} from 'ViewContext'; export type Props = ViewProps; @@ -33,30 +34,31 @@ export type Props = ViewProps; */ class View extends ReactNative.NativeComponent { static propTypes = ViewPropTypes; - static childContextTypes = ViewContextTypes; viewConfig = { uiViewClassName: 'RCTView', validAttributes: ReactNativeViewAttributes.RCTView, }; - getChildContext(): ViewChildContext { - return { - isInAParentText: false, - }; - } - + /** + * WARNING: This method will not be used in production mode as in that mode we + * replace wrapper component View with generated native wrapper RCTView. Avoid + * adding functionality this component that you'd want to be available in both + * dev and prod modes. + */ render() { - invariant( - !(this.context.isInAParentText && Platform.OS === 'android'), - 'Nesting of within is not supported on Android.', + return ( + + {hasTextAncestor => { + // TODO: Change iOS to behave the same as Android. + invariant( + !hasTextAncestor || Platform.OS !== 'android', + 'Nesting of within is not supported on Android.', + ); + return ; + }} + ); - - // WARNING: This method will not be used in production mode as in that mode we - // replace wrapper component View with generated native wrapper RCTView. Avoid - // adding functionality this component that you'd want to be available in both - // dev and prod modes. - return ; } } diff --git a/Libraries/Image/Image.android.js b/Libraries/Image/Image.android.js index 7b0ec83a8738ec..d9702700be5930 100644 --- a/Libraries/Image/Image.android.js +++ b/Libraries/Image/Image.android.js @@ -7,6 +7,7 @@ * @flow * @format */ + 'use strict'; var ImageResizeMode = require('ImageResizeMode'); @@ -18,6 +19,7 @@ var PropTypes = require('prop-types'); var ReactNativeViewAttributes = require('ReactNativeViewAttributes'); var StyleSheet = require('StyleSheet'); var StyleSheetPropType = require('StyleSheetPropType'); +const TextAncestor = require('TextAncestor'); var ViewPropTypes = require('ViewPropTypes'); var createReactClass = require('create-react-class'); @@ -26,8 +28,6 @@ var merge = require('merge'); var requireNativeComponent = require('requireNativeComponent'); var resolveAssetSource = require('resolveAssetSource'); -const {ViewContextTypes} = require('ViewContext'); - var {ImageLoader} = NativeModules; let _requestId = 1; @@ -202,8 +202,6 @@ var Image = createReactClass({ validAttributes: ReactNativeViewAttributes.RCTView, }, - contextTypes: ViewContextTypes, - render: function() { const source = resolveAssetSource(this.props.source); const defaultSource = resolveAssetSource(this.props.defaultSource); @@ -236,42 +234,44 @@ var Image = createReactClass({ ); } - if (source && (source.uri || Array.isArray(source))) { - let style; - let sources; - if (source.uri) { - const {width, height} = source; - style = flattenStyle([{width, height}, styles.base, this.props.style]); - sources = [{uri: source.uri}]; - } else { - style = flattenStyle([styles.base, this.props.style]); - sources = source; - } - - const {onLoadStart, onLoad, onLoadEnd, onError} = this.props; - const nativeProps = merge(this.props, { - style, - shouldNotifyLoadEvents: !!( - onLoadStart || - onLoad || - onLoadEnd || - onError - ), - src: sources, - headers: source.headers, - defaultSrc: defaultSource ? defaultSource.uri : null, - loadingIndicatorSrc: loadingIndicatorSource - ? loadingIndicatorSource.uri - : null, - }); + if (!source || (!source.uri && !Array.isArray(source))) { + return null; + } - if (this.context.isInAParentText) { - return ; - } else { - return ; - } + let style; + let sources; + if (source.uri) { + const {width, height} = source; + style = flattenStyle([{width, height}, styles.base, this.props.style]); + sources = [{uri: source.uri}]; + } else { + style = flattenStyle([styles.base, this.props.style]); + sources = source; } - return null; + + const {onLoadStart, onLoad, onLoadEnd, onError} = this.props; + const nativeProps = merge(this.props, { + style, + shouldNotifyLoadEvents: !!(onLoadStart || onLoad || onLoadEnd || onError), + src: sources, + headers: source.headers, + defaultSrc: defaultSource ? defaultSource.uri : null, + loadingIndicatorSrc: loadingIndicatorSource + ? loadingIndicatorSource.uri + : null, + }); + + return ( + + {hasTextAncestor => + hasTextAncestor ? ( + + ) : ( + + ) + } + + ); }, }); diff --git a/Libraries/Text/Text.js b/Libraries/Text/Text.js index d6fd56fcc62e40..d983638ac5f101 100644 --- a/Libraries/Text/Text.js +++ b/Libraries/Text/Text.js @@ -12,6 +12,7 @@ const React = require('React'); const ReactNative = require('ReactNative'); const ReactNativeViewAttributes = require('ReactNativeViewAttributes'); +const TextAncestor = require('TextAncestor'); const TextPropTypes = require('TextPropTypes'); const Touchable = require('Touchable'); const UIManager = require('UIManager'); @@ -19,11 +20,9 @@ const UIManager = require('UIManager'); const createReactNativeComponentClass = require('createReactNativeComponentClass'); const mergeFast = require('mergeFast'); const processColor = require('processColor'); -const {ViewContextTypes} = require('ViewContext'); import type {PressEvent} from 'CoreEventTypes'; import type {TextProps} from 'TextProps'; -import type {ViewChildContext} from 'ViewContext'; type State = { isHighlighted: boolean, @@ -61,8 +60,6 @@ const viewConfig = { */ class Text extends ReactNative.NativeComponent { static propTypes = TextPropTypes; - static childContextTypes = ViewContextTypes; - static contextTypes = ViewContextTypes; static defaultProps = { accessible: true, @@ -76,12 +73,6 @@ class Text extends ReactNative.NativeComponent { viewConfig = viewConfig; - getChildContext(): ViewChildContext { - return { - isInAParentText: true, - }; - } - _handlers: ?Object; _hasPressHandler(): boolean { @@ -215,11 +206,19 @@ class Text extends ReactNative.NativeComponent { style: [this.props.style, {color: 'magenta'}], }; } - if (this.context.isInAParentText) { - return ; - } else { - return ; - } + return ( + + {hasTextAncestor => + hasTextAncestor ? ( + + ) : ( + + + + ) + } + + ); } } diff --git a/Libraries/Components/View/ViewContext.js b/Libraries/Text/TextAncestor.js similarity index 53% rename from Libraries/Components/View/ViewContext.js rename to Libraries/Text/TextAncestor.js index 81879aa35ecfa1..147d9763b2d6d4 100644 --- a/Libraries/Components/View/ViewContext.js +++ b/Libraries/Text/TextAncestor.js @@ -7,16 +7,12 @@ * @flow * @format */ -'use strict'; -const PropTypes = require('prop-types'); +'use strict'; -export type ViewChildContext = {| - +isInAParentText: boolean, -|}; +const React = require('React'); -module.exports = { - ViewContextTypes: { - isInAParentText: PropTypes.bool, - }, -}; +/** + * Whether the current element is the descendant of a element. + */ +module.exports = React.createContext(false);