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 {
|
||||
invariant(
|
||||
typeof Component === 'string' ||
|
||||
typeof Component !== 'function' ||
|
||||
(Component.prototype && Component.prototype.isReactComponent),
|
||||
'`createAnimatedComponent` does not support stateless functional components; ' +
|
||||
'use a class component instead.',
|
||||
|
|
|
@ -4,23 +4,22 @@
|
|||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const Platform = require('Platform');
|
||||
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 invariant = require('fbjs/lib/invariant');
|
||||
const requireNativeComponent = require('requireNativeComponent');
|
||||
|
||||
import type {NativeComponent} from 'ReactNative';
|
||||
import type {ViewProps} from 'ViewPropTypes';
|
||||
|
||||
export type Props = ViewProps;
|
||||
|
@ -32,50 +31,25 @@ export type Props = ViewProps;
|
|||
*
|
||||
* @see http://facebook.github.io/react-native/docs/view.html
|
||||
*/
|
||||
class View extends ReactNative.NativeComponent<Props> {
|
||||
static propTypes = ViewPropTypes;
|
||||
|
||||
viewConfig = {
|
||||
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, {
|
||||
const RCTView = requireNativeComponent(
|
||||
'RCTView',
|
||||
{
|
||||
propTypes: ViewPropTypes,
|
||||
},
|
||||
{
|
||||
nativeOnly: {
|
||||
nativeBackgroundAndroid: true,
|
||||
nativeForegroundAndroid: true,
|
||||
},
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
if (__DEV__) {
|
||||
const UIManager = require('UIManager');
|
||||
const viewConfig =
|
||||
(UIManager.viewConfigs && UIManager.viewConfigs.RCTView) || {};
|
||||
for (const prop in viewConfig.nativeProps) {
|
||||
const viewAny: any = View; // Appease flow
|
||||
if (!viewAny.propTypes[prop] && !ReactNativeStyleAttributes[prop]) {
|
||||
if (!ViewPropTypes[prop] && !ReactNativeStyleAttributes[prop]) {
|
||||
throw new Error(
|
||||
'View is missing propType for native prop `' + prop + '`',
|
||||
);
|
||||
|
@ -85,8 +59,20 @@ if (__DEV__) {
|
|||
|
||||
let ViewToExport = RCTView;
|
||||
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): typeof View);
|
||||
module.exports = ((ViewToExport: any): Class<NativeComponent<ViewProps, any>>);
|
||||
|
|
|
@ -3,14 +3,20 @@
|
|||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = moduleName => {
|
||||
module.exports = (moduleName, instanceMethods) => {
|
||||
const RealComponent = require.requireActual(moduleName);
|
||||
const React = require('react');
|
||||
|
||||
const Component = class extends RealComponent {
|
||||
const SuperClass =
|
||||
typeof RealComponent === 'function' ? RealComponent : React.Component;
|
||||
|
||||
const Component = class extends SuperClass {
|
||||
render() {
|
||||
const name = RealComponent.displayName || RealComponent.name;
|
||||
|
||||
|
@ -21,5 +27,10 @@ module.exports = moduleName => {
|
|||
);
|
||||
}
|
||||
};
|
||||
|
||||
if (instanceMethods != null) {
|
||||
Object.assign(Component.prototype, instanceMethods);
|
||||
}
|
||||
|
||||
return Component;
|
||||
};
|
||||
|
|
|
@ -38,7 +38,7 @@ jest
|
|||
.mock('Text', () => mockComponent('Text'))
|
||||
.mock('TextInput', () => mockComponent('TextInput'))
|
||||
.mock('Modal', () => mockComponent('Modal'))
|
||||
.mock('View', () => mockComponent('View'))
|
||||
.mock('View', () => mockComponent('View', MockNativeMethods))
|
||||
.mock('RefreshControl', () => require.requireMock('RefreshControlMock'))
|
||||
.mock('ScrollView', () => require.requireMock('ScrollViewMock'))
|
||||
.mock(
|
||||
|
|
Loading…
Reference in New Issue