Skip to content

Commit 3e534b9

Browse files
yungstersfacebook-github-bot
authored andcommitted
RN: Switch View to React.forwardRef
Reviewed By: bvaughn, sophiebits Differential Revision: D7896711 fbshipit-source-id: c10c8a14a00ac2d67605e6e4fe1a341b4688fdd8
1 parent e1339bc commit 3e534b9

File tree

4 files changed

+45
-48
lines changed

4 files changed

+45
-48
lines changed

Libraries/Animated/src/createAnimatedComponent.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const invariant = require('fbjs/lib/invariant');
1818

1919
function createAnimatedComponent(Component: any): any {
2020
invariant(
21-
typeof Component === 'string' ||
21+
typeof Component !== 'function' ||
2222
(Component.prototype && Component.prototype.isReactComponent),
2323
'`createAnimatedComponent` does not support stateless functional components; ' +
2424
'use a class component instead.',

Libraries/Components/View/View.js

+29-43
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,22 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @flow
87
* @format
8+
* @flow
99
*/
1010

1111
'use strict';
1212

1313
const Platform = require('Platform');
1414
const React = require('React');
15-
const ReactNative = require('ReactNative');
1615
const ReactNativeStyleAttributes = require('ReactNativeStyleAttributes');
17-
const ReactNativeViewAttributes = require('ReactNativeViewAttributes');
1816
const TextAncestor = require('TextAncestor');
1917
const ViewPropTypes = require('ViewPropTypes');
2018

2119
const invariant = require('fbjs/lib/invariant');
2220
const requireNativeComponent = require('requireNativeComponent');
2321

22+
import type {NativeComponent} from 'ReactNative';
2423
import type {ViewProps} from 'ViewPropTypes';
2524

2625
export type Props = ViewProps;
@@ -32,50 +31,25 @@ export type Props = ViewProps;
3231
*
3332
* @see http://facebook.github.io/react-native/docs/view.html
3433
*/
35-
class View extends ReactNative.NativeComponent<Props> {
36-
static propTypes = ViewPropTypes;
37-
38-
viewConfig = {
39-
uiViewClassName: 'RCTView',
40-
validAttributes: ReactNativeViewAttributes.RCTView,
41-
};
42-
43-
/**
44-
* WARNING: This method will not be used in production mode as in that mode we
45-
* replace wrapper component View with generated native wrapper RCTView. Avoid
46-
* adding functionality this component that you'd want to be available in both
47-
* dev and prod modes.
48-
*/
49-
render() {
50-
return (
51-
<TextAncestor.Consumer>
52-
{hasTextAncestor => {
53-
// TODO: Change iOS to behave the same as Android.
54-
invariant(
55-
!hasTextAncestor || Platform.OS !== 'android',
56-
'Nesting of <View> within <Text> is not supported on Android.',
57-
);
58-
return <RCTView {...this.props} />;
59-
}}
60-
</TextAncestor.Consumer>
61-
);
62-
}
63-
}
64-
65-
const RCTView = requireNativeComponent('RCTView', View, {
66-
nativeOnly: {
67-
nativeBackgroundAndroid: true,
68-
nativeForegroundAndroid: true,
34+
const RCTView = requireNativeComponent(
35+
'RCTView',
36+
{
37+
propTypes: ViewPropTypes,
38+
},
39+
{
40+
nativeOnly: {
41+
nativeBackgroundAndroid: true,
42+
nativeForegroundAndroid: true,
43+
},
6944
},
70-
});
45+
);
7146

7247
if (__DEV__) {
7348
const UIManager = require('UIManager');
7449
const viewConfig =
7550
(UIManager.viewConfigs && UIManager.viewConfigs.RCTView) || {};
7651
for (const prop in viewConfig.nativeProps) {
77-
const viewAny: any = View; // Appease flow
78-
if (!viewAny.propTypes[prop] && !ReactNativeStyleAttributes[prop]) {
52+
if (!ViewPropTypes[prop] && !ReactNativeStyleAttributes[prop]) {
7953
throw new Error(
8054
'View is missing propType for native prop `' + prop + '`',
8155
);
@@ -85,8 +59,20 @@ if (__DEV__) {
8559

8660
let ViewToExport = RCTView;
8761
if (__DEV__) {
88-
ViewToExport = View;
62+
// $FlowFixMe - TODO T29156721 `React.forwardRef` is not defined in Flow, yet.
63+
ViewToExport = React.forwardRef((props, ref) => (
64+
<TextAncestor.Consumer>
65+
{hasTextAncestor => {
66+
// TODO: Change iOS to behave the same as Android.
67+
invariant(
68+
!hasTextAncestor || Platform.OS !== 'android',
69+
'Nesting of <View> within <Text> is not supported on Android.',
70+
);
71+
return <RCTView {...props} ref={ref} />;
72+
}}
73+
</TextAncestor.Consumer>
74+
));
75+
ViewToExport.displayName = 'View';
8976
}
9077

91-
// No one should depend on the DEV-mode createClass View wrapper.
92-
module.exports = ((ViewToExport: any): typeof View);
78+
module.exports = ((ViewToExport: any): Class<NativeComponent<ViewProps, any>>);

jest/mockComponent.js

+14-3
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,34 @@
33
*
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @format
68
*/
9+
710
'use strict';
811

9-
module.exports = moduleName => {
12+
module.exports = (moduleName, instanceMethods) => {
1013
const RealComponent = require.requireActual(moduleName);
1114
const React = require('react');
1215

13-
const Component = class extends RealComponent {
16+
const SuperClass =
17+
typeof RealComponent === 'function' ? RealComponent : React.Component;
18+
19+
const Component = class extends SuperClass {
1420
render() {
1521
const name = RealComponent.displayName || RealComponent.name;
1622

1723
return React.createElement(
18-
name.replace(/^(RCT|RK)/,''),
24+
name.replace(/^(RCT|RK)/, ''),
1925
this.props,
2026
this.props.children,
2127
);
2228
}
2329
};
30+
31+
if (instanceMethods != null) {
32+
Object.assign(Component.prototype, instanceMethods);
33+
}
34+
2435
return Component;
2536
};

jest/setup.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ jest
3838
.mock('Text', () => mockComponent('Text'))
3939
.mock('TextInput', () => mockComponent('TextInput'))
4040
.mock('Modal', () => mockComponent('Modal'))
41-
.mock('View', () => mockComponent('View'))
41+
.mock('View', () => mockComponent('View', MockNativeMethods))
4242
.mock('RefreshControl', () => require.requireMock('RefreshControlMock'))
4343
.mock('ScrollView', () => require.requireMock('ScrollViewMock'))
4444
.mock(

0 commit comments

Comments
 (0)