RN: Simpify `requireNativeComponent`
Reviewed By: sahrens Differential Revision: D7893592 fbshipit-source-id: bfe7772ff2fa785fc7c5ad1f7dc0dbe97b6ffb11
This commit is contained in:
parent
28d37781c6
commit
b549e364e0
|
@ -7,6 +7,7 @@
|
|||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const Platform = require('Platform');
|
||||
|
@ -24,6 +25,14 @@ const verifyPropTypes = require('verifyPropTypes');
|
|||
const invariant = require('fbjs/lib/invariant');
|
||||
const warning = require('fbjs/lib/warning');
|
||||
|
||||
import type {ComponentInterface} from 'verifyPropTypes';
|
||||
|
||||
type ExtraOptions = $ReadOnly<{|
|
||||
nativeOnly?: $ReadOnly<{
|
||||
[propName: string]: boolean,
|
||||
}>,
|
||||
|}>;
|
||||
|
||||
/**
|
||||
* Used to create React components that directly wrap native component
|
||||
* implementations. Config information is extracted from data exported from the
|
||||
|
@ -39,81 +48,23 @@ const warning = require('fbjs/lib/warning');
|
|||
* Common types are lined up with the appropriate prop differs with
|
||||
* `TypeToDifferMap`. Non-scalar types not in the map default to `deepDiffer`.
|
||||
*/
|
||||
import type {ComponentInterface} from 'verifyPropTypes';
|
||||
|
||||
let hasAttachedDefaultEventTypes: boolean = false;
|
||||
|
||||
function requireNativeComponent(
|
||||
const requireNativeComponent = (
|
||||
viewName: string,
|
||||
componentInterface?: ?ComponentInterface,
|
||||
extraConfig?: ?{nativeOnly?: Object},
|
||||
): React$ComponentType<any> | string {
|
||||
function attachDefaultEventTypes(viewConfig: any) {
|
||||
// This is supported on UIManager platforms (ex: Android),
|
||||
// as lazy view managers are not implemented for all platforms.
|
||||
// See [UIManager] for details on constants and implementations.
|
||||
if (UIManager.ViewManagerNames) {
|
||||
// Lazy view managers enabled.
|
||||
viewConfig = merge(viewConfig, UIManager.getDefaultEventTypes());
|
||||
} else {
|
||||
viewConfig.bubblingEventTypes = merge(
|
||||
viewConfig.bubblingEventTypes,
|
||||
UIManager.genericBubblingEventTypes,
|
||||
);
|
||||
viewConfig.directEventTypes = merge(
|
||||
viewConfig.directEventTypes,
|
||||
UIManager.genericDirectEventTypes,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function merge(destination: ?Object, source: ?Object): ?Object {
|
||||
if (!source) {
|
||||
return destination;
|
||||
}
|
||||
if (!destination) {
|
||||
return source;
|
||||
}
|
||||
|
||||
for (const key in source) {
|
||||
if (!source.hasOwnProperty(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var sourceValue = source[key];
|
||||
if (destination.hasOwnProperty(key)) {
|
||||
const destinationValue = destination[key];
|
||||
if (
|
||||
typeof sourceValue === 'object' &&
|
||||
typeof destinationValue === 'object'
|
||||
) {
|
||||
sourceValue = merge(destinationValue, sourceValue);
|
||||
}
|
||||
}
|
||||
destination[key] = sourceValue;
|
||||
}
|
||||
return destination;
|
||||
}
|
||||
|
||||
// Don't load the ViewConfig from UIManager until it's needed for rendering.
|
||||
// Lazy-loading this can help avoid Prepack deopts.
|
||||
function getViewConfig() {
|
||||
extraConfig?: ?ExtraOptions,
|
||||
): string =>
|
||||
createReactNativeComponentClass(viewName, () => {
|
||||
const viewConfig = UIManager[viewName];
|
||||
|
||||
invariant(
|
||||
viewConfig != null && viewConfig.NativeProps != null,
|
||||
'Native component for "%s" does not exist',
|
||||
'requireNativeComponent: "%s" was not found in the UIManager.',
|
||||
viewName,
|
||||
);
|
||||
|
||||
viewConfig.uiViewClassName = viewName;
|
||||
viewConfig.validAttributes = {};
|
||||
viewConfig.propTypes =
|
||||
componentInterface == null ? null : componentInterface.propTypes;
|
||||
|
||||
let baseModuleName = viewConfig.baseModuleName;
|
||||
let bubblingEventTypes = viewConfig.bubblingEventTypes;
|
||||
let directEventTypes = viewConfig.directEventTypes;
|
||||
// TODO: This seems like a whole lot of runtime initialization for every
|
||||
// native component that can be either avoided or simplified.
|
||||
let {baseModuleName, bubblingEventTypes, directEventTypes} = viewConfig;
|
||||
let nativeProps = viewConfig.NativeProps;
|
||||
while (baseModuleName) {
|
||||
const baseModule = UIManager[baseModuleName];
|
||||
|
@ -137,32 +88,40 @@ function requireNativeComponent(
|
|||
}
|
||||
}
|
||||
|
||||
viewConfig.bubblingEventTypes = bubblingEventTypes;
|
||||
viewConfig.directEventTypes = directEventTypes;
|
||||
const viewAttributes = {};
|
||||
|
||||
for (const key in nativeProps) {
|
||||
const typeName = nativeProps[key];
|
||||
const diff = getDifferForType(typeName);
|
||||
const process = getProcessorForType(typeName);
|
||||
|
||||
viewConfig.validAttributes[key] =
|
||||
viewAttributes[key] =
|
||||
diff == null && process == null ? true : {diff, process};
|
||||
}
|
||||
|
||||
// Unfortunately, the current set up puts the style properties on the top
|
||||
// level props object. We also need to add the nested form for API
|
||||
// compatibility. This allows these props on both the top level and the
|
||||
// nested style level. TODO: Move these to nested declarations on the
|
||||
// native side.
|
||||
viewConfig.validAttributes.style = ReactNativeStyleAttributes;
|
||||
// Unfortunately, the current setup declares style properties as top-level
|
||||
// props. This makes it so we allow style properties in the `style` prop.
|
||||
// TODO: Move style properties into a `style` prop and disallow them as
|
||||
// top-level props on the native side.
|
||||
viewAttributes.style = ReactNativeStyleAttributes;
|
||||
|
||||
Object.assign(viewConfig, {
|
||||
uiViewClassName: viewName,
|
||||
validAttributes: viewAttributes,
|
||||
propTypes:
|
||||
componentInterface == null ? null : componentInterface.propTypes,
|
||||
bubblingEventTypes,
|
||||
directEventTypes,
|
||||
});
|
||||
|
||||
if (__DEV__) {
|
||||
componentInterface &&
|
||||
if (componentInterface != null) {
|
||||
verifyPropTypes(
|
||||
componentInterface,
|
||||
viewConfig,
|
||||
extraConfig && extraConfig.nativeOnly,
|
||||
extraConfig == null ? null : extraConfig.nativeOnly,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasAttachedDefaultEventTypes) {
|
||||
|
@ -171,9 +130,57 @@ function requireNativeComponent(
|
|||
}
|
||||
|
||||
return viewConfig;
|
||||
});
|
||||
|
||||
// TODO: Figure out how this makes sense. We're using a global boolean to only
|
||||
// initialize this on the first eagerly initialized native component.
|
||||
let hasAttachedDefaultEventTypes = false;
|
||||
function attachDefaultEventTypes(viewConfig: any) {
|
||||
// This is supported on UIManager platforms (ex: Android),
|
||||
// as lazy view managers are not implemented for all platforms.
|
||||
// See [UIManager] for details on constants and implementations.
|
||||
if (UIManager.ViewManagerNames) {
|
||||
// Lazy view managers enabled.
|
||||
viewConfig = merge(viewConfig, UIManager.getDefaultEventTypes());
|
||||
} else {
|
||||
viewConfig.bubblingEventTypes = merge(
|
||||
viewConfig.bubblingEventTypes,
|
||||
UIManager.genericBubblingEventTypes,
|
||||
);
|
||||
viewConfig.directEventTypes = merge(
|
||||
viewConfig.directEventTypes,
|
||||
UIManager.genericDirectEventTypes,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Figure out how to avoid all this runtime initialization cost.
|
||||
function merge(destination: ?Object, source: ?Object): ?Object {
|
||||
if (!source) {
|
||||
return destination;
|
||||
}
|
||||
if (!destination) {
|
||||
return source;
|
||||
}
|
||||
|
||||
return createReactNativeComponentClass(viewName, getViewConfig);
|
||||
for (const key in source) {
|
||||
if (!source.hasOwnProperty(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let sourceValue = source[key];
|
||||
if (destination.hasOwnProperty(key)) {
|
||||
const destinationValue = destination[key];
|
||||
if (
|
||||
typeof sourceValue === 'object' &&
|
||||
typeof destinationValue === 'object'
|
||||
) {
|
||||
sourceValue = merge(destinationValue, sourceValue);
|
||||
}
|
||||
}
|
||||
destination[key] = sourceValue;
|
||||
}
|
||||
return destination;
|
||||
}
|
||||
|
||||
function getDifferForType(
|
||||
|
|
Loading…
Reference in New Issue