RN: Switch `View` to `React.forwardRef`
Reviewed By: bvaughn, sophiebits Differential Revision: D7896711 fbshipit-source-id: c10c8a14a00ac2d67605e6e4fe1a341b4688fdd8
This commit is contained in:
parent
e1339bc183
commit
3e534b9aab
|
@ -18,7 +18,7 @@ const invariant = require('fbjs/lib/invariant');
|
||||||
|
|
||||||
function createAnimatedComponent(Component: any): any {
|
function createAnimatedComponent(Component: any): any {
|
||||||
invariant(
|
invariant(
|
||||||
typeof Component === 'string' ||
|
typeof Component !== 'function' ||
|
||||||
(Component.prototype && Component.prototype.isReactComponent),
|
(Component.prototype && Component.prototype.isReactComponent),
|
||||||
'`createAnimatedComponent` does not support stateless functional components; ' +
|
'`createAnimatedComponent` does not support stateless functional components; ' +
|
||||||
'use a class component instead.',
|
'use a class component instead.',
|
||||||
|
|
|
@ -4,23 +4,22 @@
|
||||||
* This source code is licensed under the MIT license found in the
|
* This source code is licensed under the MIT license found in the
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*
|
*
|
||||||
* @flow
|
|
||||||
* @format
|
* @format
|
||||||
|
* @flow
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const Platform = require('Platform');
|
const Platform = require('Platform');
|
||||||
const React = require('React');
|
const React = require('React');
|
||||||
const ReactNative = require('ReactNative');
|
|
||||||
const ReactNativeStyleAttributes = require('ReactNativeStyleAttributes');
|
const ReactNativeStyleAttributes = require('ReactNativeStyleAttributes');
|
||||||
const ReactNativeViewAttributes = require('ReactNativeViewAttributes');
|
|
||||||
const TextAncestor = require('TextAncestor');
|
const TextAncestor = require('TextAncestor');
|
||||||
const ViewPropTypes = require('ViewPropTypes');
|
const ViewPropTypes = require('ViewPropTypes');
|
||||||
|
|
||||||
const invariant = require('fbjs/lib/invariant');
|
const invariant = require('fbjs/lib/invariant');
|
||||||
const requireNativeComponent = require('requireNativeComponent');
|
const requireNativeComponent = require('requireNativeComponent');
|
||||||
|
|
||||||
|
import type {NativeComponent} from 'ReactNative';
|
||||||
import type {ViewProps} from 'ViewPropTypes';
|
import type {ViewProps} from 'ViewPropTypes';
|
||||||
|
|
||||||
export type Props = ViewProps;
|
export type Props = ViewProps;
|
||||||
|
@ -32,50 +31,25 @@ export type Props = ViewProps;
|
||||||
*
|
*
|
||||||
* @see http://facebook.github.io/react-native/docs/view.html
|
* @see http://facebook.github.io/react-native/docs/view.html
|
||||||
*/
|
*/
|
||||||
class View extends ReactNative.NativeComponent<Props> {
|
const RCTView = requireNativeComponent(
|
||||||
static propTypes = ViewPropTypes;
|
'RCTView',
|
||||||
|
{
|
||||||
viewConfig = {
|
propTypes: ViewPropTypes,
|
||||||
uiViewClassName: 'RCTView',
|
|
||||||
validAttributes: ReactNativeViewAttributes.RCTView,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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() {
|
|
||||||
return (
|
|
||||||
<TextAncestor.Consumer>
|
|
||||||
{hasTextAncestor => {
|
|
||||||
// TODO: Change iOS to behave the same as Android.
|
|
||||||
invariant(
|
|
||||||
!hasTextAncestor || Platform.OS !== 'android',
|
|
||||||
'Nesting of <View> within <Text> is not supported on Android.',
|
|
||||||
);
|
|
||||||
return <RCTView {...this.props} />;
|
|
||||||
}}
|
|
||||||
</TextAncestor.Consumer>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const RCTView = requireNativeComponent('RCTView', View, {
|
|
||||||
nativeOnly: {
|
|
||||||
nativeBackgroundAndroid: true,
|
|
||||||
nativeForegroundAndroid: true,
|
|
||||||
},
|
},
|
||||||
});
|
{
|
||||||
|
nativeOnly: {
|
||||||
|
nativeBackgroundAndroid: true,
|
||||||
|
nativeForegroundAndroid: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
const UIManager = require('UIManager');
|
const UIManager = require('UIManager');
|
||||||
const viewConfig =
|
const viewConfig =
|
||||||
(UIManager.viewConfigs && UIManager.viewConfigs.RCTView) || {};
|
(UIManager.viewConfigs && UIManager.viewConfigs.RCTView) || {};
|
||||||
for (const prop in viewConfig.nativeProps) {
|
for (const prop in viewConfig.nativeProps) {
|
||||||
const viewAny: any = View; // Appease flow
|
if (!ViewPropTypes[prop] && !ReactNativeStyleAttributes[prop]) {
|
||||||
if (!viewAny.propTypes[prop] && !ReactNativeStyleAttributes[prop]) {
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'View is missing propType for native prop `' + prop + '`',
|
'View is missing propType for native prop `' + prop + '`',
|
||||||
);
|
);
|
||||||
|
@ -85,8 +59,20 @@ if (__DEV__) {
|
||||||
|
|
||||||
let ViewToExport = RCTView;
|
let ViewToExport = RCTView;
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
ViewToExport = View;
|
// $FlowFixMe - TODO T29156721 `React.forwardRef` is not defined in Flow, yet.
|
||||||
|
ViewToExport = React.forwardRef((props, ref) => (
|
||||||
|
<TextAncestor.Consumer>
|
||||||
|
{hasTextAncestor => {
|
||||||
|
// TODO: Change iOS to behave the same as Android.
|
||||||
|
invariant(
|
||||||
|
!hasTextAncestor || Platform.OS !== 'android',
|
||||||
|
'Nesting of <View> within <Text> is not supported on Android.',
|
||||||
|
);
|
||||||
|
return <RCTView {...props} ref={ref} />;
|
||||||
|
}}
|
||||||
|
</TextAncestor.Consumer>
|
||||||
|
));
|
||||||
|
ViewToExport.displayName = 'View';
|
||||||
}
|
}
|
||||||
|
|
||||||
// No one should depend on the DEV-mode createClass View wrapper.
|
module.exports = ((ViewToExport: any): Class<NativeComponent<ViewProps, any>>);
|
||||||
module.exports = ((ViewToExport: any): typeof View);
|
|
||||||
|
|
|
@ -3,23 +3,34 @@
|
||||||
*
|
*
|
||||||
* This source code is licensed under the MIT license found in the
|
* This source code is licensed under the MIT license found in the
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*
|
||||||
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
module.exports = moduleName => {
|
module.exports = (moduleName, instanceMethods) => {
|
||||||
const RealComponent = require.requireActual(moduleName);
|
const RealComponent = require.requireActual(moduleName);
|
||||||
const React = require('react');
|
const React = require('react');
|
||||||
|
|
||||||
const Component = class extends RealComponent {
|
const SuperClass =
|
||||||
|
typeof RealComponent === 'function' ? RealComponent : React.Component;
|
||||||
|
|
||||||
|
const Component = class extends SuperClass {
|
||||||
render() {
|
render() {
|
||||||
const name = RealComponent.displayName || RealComponent.name;
|
const name = RealComponent.displayName || RealComponent.name;
|
||||||
|
|
||||||
return React.createElement(
|
return React.createElement(
|
||||||
name.replace(/^(RCT|RK)/,''),
|
name.replace(/^(RCT|RK)/, ''),
|
||||||
this.props,
|
this.props,
|
||||||
this.props.children,
|
this.props.children,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (instanceMethods != null) {
|
||||||
|
Object.assign(Component.prototype, instanceMethods);
|
||||||
|
}
|
||||||
|
|
||||||
return Component;
|
return Component;
|
||||||
};
|
};
|
||||||
|
|
|
@ -38,7 +38,7 @@ jest
|
||||||
.mock('Text', () => mockComponent('Text'))
|
.mock('Text', () => mockComponent('Text'))
|
||||||
.mock('TextInput', () => mockComponent('TextInput'))
|
.mock('TextInput', () => mockComponent('TextInput'))
|
||||||
.mock('Modal', () => mockComponent('Modal'))
|
.mock('Modal', () => mockComponent('Modal'))
|
||||||
.mock('View', () => mockComponent('View'))
|
.mock('View', () => mockComponent('View', MockNativeMethods))
|
||||||
.mock('RefreshControl', () => require.requireMock('RefreshControlMock'))
|
.mock('RefreshControl', () => require.requireMock('RefreshControlMock'))
|
||||||
.mock('ScrollView', () => require.requireMock('ScrollViewMock'))
|
.mock('ScrollView', () => require.requireMock('ScrollViewMock'))
|
||||||
.mock(
|
.mock(
|
||||||
|
|
Loading…
Reference in New Issue