mirror of
https://github.com/status-im/react-native.git
synced 2025-02-24 07:08:27 +00:00
Summary: This adds a synchronous method that JS can call to load view managers. Notably, we don't have an exact way to go from a JS name to the native view manager, so this naively adds 'Manager' to the end. After lazily loading the view, it makes sure to cache all its values in native and JS, as further calls from JS will fail. Reviewed By: PeteTheHeat Differential Revision: D10204314 fbshipit-source-id: ebf42a85dcc467f3b4c5d6e18e49e04f9e8aa4f9
165 lines
5.3 KiB
JavaScript
165 lines
5.3 KiB
JavaScript
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* @flow strict-local
|
|
* @format
|
|
*/
|
|
'use strict';
|
|
|
|
const NativeModules = require('NativeModules');
|
|
const Platform = require('Platform');
|
|
const UIManagerProperties = require('UIManagerProperties');
|
|
|
|
const defineLazyObjectProperty = require('defineLazyObjectProperty');
|
|
const invariant = require('fbjs/lib/invariant');
|
|
|
|
const {UIManager} = NativeModules;
|
|
const viewManagerConfigs = {};
|
|
|
|
invariant(
|
|
UIManager,
|
|
'UIManager is undefined. The native module config is probably incorrect.',
|
|
);
|
|
|
|
// In past versions of ReactNative users called UIManager.takeSnapshot()
|
|
// However takeSnapshot was moved to ReactNative in order to support flat
|
|
// bundles and to avoid a cyclic dependency between UIManager and ReactNative.
|
|
// UIManager.takeSnapshot still exists though. In order to avoid confusion or
|
|
// accidental usage, mask the method with a deprecation warning.
|
|
UIManager.__takeSnapshot = UIManager.takeSnapshot;
|
|
UIManager.takeSnapshot = function() {
|
|
invariant(
|
|
false,
|
|
'UIManager.takeSnapshot should not be called directly. ' +
|
|
'Use ReactNative.takeSnapshot instead.',
|
|
);
|
|
};
|
|
const triedLoadingConfig = new Set();
|
|
UIManager.getViewManagerConfig = function(viewManagerName: string) {
|
|
if (
|
|
viewManagerConfigs[viewManagerName] === undefined &&
|
|
UIManager.getConstantsForViewManager
|
|
) {
|
|
try {
|
|
viewManagerConfigs[
|
|
viewManagerName
|
|
] = UIManager.getConstantsForViewManager(viewManagerName);
|
|
} catch (e) {
|
|
viewManagerConfigs[viewManagerName] = null;
|
|
}
|
|
}
|
|
|
|
const config = viewManagerConfigs[viewManagerName];
|
|
if (config) {
|
|
return config;
|
|
}
|
|
|
|
if (UIManager.lazilyLoadView && !triedLoadingConfig.has(viewManagerName)) {
|
|
const result = UIManager.lazilyLoadView(viewManagerName);
|
|
triedLoadingConfig.add(viewManagerName);
|
|
if (result.viewConfig) {
|
|
UIManager[viewManagerName] = result.viewConfig;
|
|
lazifyViewManagerConfig(viewManagerName);
|
|
}
|
|
}
|
|
|
|
return viewManagerConfigs[viewManagerName];
|
|
};
|
|
|
|
function lazifyViewManagerConfig(viewName) {
|
|
const viewConfig = UIManager[viewName];
|
|
if (viewConfig.Manager) {
|
|
viewManagerConfigs[viewName] = viewConfig;
|
|
defineLazyObjectProperty(viewConfig, 'Constants', {
|
|
get: () => {
|
|
const viewManager = NativeModules[viewConfig.Manager];
|
|
const constants = {};
|
|
viewManager &&
|
|
Object.keys(viewManager).forEach(key => {
|
|
const value = viewManager[key];
|
|
if (typeof value !== 'function') {
|
|
constants[key] = value;
|
|
}
|
|
});
|
|
return constants;
|
|
},
|
|
});
|
|
defineLazyObjectProperty(viewConfig, 'Commands', {
|
|
get: () => {
|
|
const viewManager = NativeModules[viewConfig.Manager];
|
|
const commands = {};
|
|
let index = 0;
|
|
viewManager &&
|
|
Object.keys(viewManager).forEach(key => {
|
|
const value = viewManager[key];
|
|
if (typeof value === 'function') {
|
|
commands[key] = index++;
|
|
}
|
|
});
|
|
return commands;
|
|
},
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Copies the ViewManager constants and commands into UIManager. This is
|
|
* only needed for iOS, which puts the constants in the ViewManager
|
|
* namespace instead of UIManager, unlike Android.
|
|
*/
|
|
if (Platform.OS === 'ios') {
|
|
Object.keys(UIManager).forEach(viewName => {
|
|
lazifyViewManagerConfig(viewName);
|
|
});
|
|
} else if (UIManager.ViewManagerNames) {
|
|
// We want to add all the view managers to the UIManager.
|
|
// However, the way things are set up, the list of view managers is not known at compile time.
|
|
// As Prepack runs at compile it, it cannot process this loop.
|
|
// So we wrap it in a special __residual call, which basically tells Prepack to ignore it.
|
|
let residual = global.__residual
|
|
? global.__residual
|
|
: (_, f, ...args) => f.apply(undefined, args);
|
|
residual(
|
|
'void',
|
|
(UIManager, defineLazyObjectProperty) => {
|
|
UIManager.ViewManagerNames.forEach(viewManagerName => {
|
|
defineLazyObjectProperty(UIManager, viewManagerName, {
|
|
get: () => UIManager.getConstantsForViewManager(viewManagerName),
|
|
});
|
|
});
|
|
},
|
|
UIManager,
|
|
defineLazyObjectProperty,
|
|
);
|
|
|
|
// As Prepack now no longer knows which properties exactly the UIManager has,
|
|
// we also tell Prepack that it has only partial knowledge of the UIManager,
|
|
// so that any accesses to unknown properties along the global code will fail
|
|
// when Prepack encounters them.
|
|
if (global.__makePartial) global.__makePartial(UIManager);
|
|
}
|
|
|
|
if (__DEV__) {
|
|
Object.keys(UIManager).forEach(viewManagerName => {
|
|
if (!UIManagerProperties.includes(viewManagerName)) {
|
|
if (!viewManagerConfigs[viewManagerName]) {
|
|
viewManagerConfigs[viewManagerName] = UIManager[viewManagerName];
|
|
}
|
|
defineLazyObjectProperty(UIManager, viewManagerName, {
|
|
get: () => {
|
|
console.warn(
|
|
`Accessing view manager configs directly off UIManager via UIManager['${viewManagerName}'] ` +
|
|
`is no longer supported. Use UIManager.getViewManager('${viewManagerName}') instead.`,
|
|
);
|
|
return UIManager.getViewManagerConfig(viewManagerName);
|
|
},
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
module.exports = UIManager;
|