diff --git a/Libraries/ReactNative/UIManager.js b/Libraries/ReactNative/UIManager.js index c93563011..ddc06f343 100644 --- a/Libraries/ReactNative/UIManager.js +++ b/Libraries/ReactNative/UIManager.js @@ -11,11 +11,13 @@ 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, @@ -36,7 +38,20 @@ UIManager.takeSnapshot = function() { ); }; UIManager.getViewManagerConfig = function(viewManagerName: string) { - return UIManager[viewManagerName]; + if ( + viewManagerConfigs[viewManagerName] === undefined && + UIManager.getConstantsForViewManager + ) { + try { + viewManagerConfigs[ + viewManagerName + ] = UIManager.getConstantsForViewManager(viewManagerName); + } catch (e) { + viewManagerConfigs[viewManagerName] = null; + } + } + + return viewManagerConfigs[viewManagerName]; }; /** @@ -48,6 +63,7 @@ if (Platform.OS === 'ios') { Object.keys(UIManager).forEach(viewName => { const viewConfig = UIManager[viewName]; if (viewConfig.Manager) { + viewManagerConfigs[viewName] = viewConfig; defineLazyObjectProperty(viewConfig, 'Constants', { get: () => { const viewManager = NativeModules[viewConfig.Manager]; @@ -107,4 +123,20 @@ if (Platform.OS === 'ios') { if (global.__makePartial) global.__makePartial(UIManager); } +if (__DEV__) { + Object.keys(UIManager).forEach(viewManagerName => { + if (!UIManagerProperties.includes(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; diff --git a/Libraries/ReactNative/UIManagerProperties.js b/Libraries/ReactNative/UIManagerProperties.js new file mode 100644 index 000000000..a579b6047 --- /dev/null +++ b/Libraries/ReactNative/UIManagerProperties.js @@ -0,0 +1,67 @@ +/** + * 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'; + +/** + * The list of non-ViewManager related UIManager properties. + * + * In an effort to improve startup performance by lazily loading view managers, + * the interface to access view managers will change from + * UIManager['viewManagerName'] to UIManager.getViewManager('viewManagerName'). + * By using a function call instead of a property access, the UIManager will + * be able to initialize and load the required view manager from native + * synchronously. All of React Native's core components have been updated to + * use getViewManager(). For the next few releases, any usage of + * UIManager['viewManagerName'] will result in a warning. Because React Native + * does not support Proxy objects, a view manager access is implied if any of + * UIManager's properties that are not one of the properties below is being + * accessed. Once UIManager property accesses for view managers has been fully + * deprecated, this file will also be removed. + */ +module.exports = [ + 'clearJSResponder', + 'configureNextLayoutAnimation', + 'createView', + 'dismissPopupMenu', + 'dispatchViewManagerCommand', + 'findSubviewIn', + 'getConstantsForViewManager', + 'getDefaultEventTypes', + 'manageChildren', + 'measure', + 'measureInWindow', + 'measureLayout', + 'measureLayoutRelativeToParent', + 'playTouchSound', + 'removeRootView', + 'removeSubviewsFromContainerWithID', + 'replaceExistingNonRootView', + 'sendAccessibilityEvent', + 'setChildren', + 'setJSResponder', + 'setLayoutAnimationEnabledExperimental', + 'showPopupMenu', + 'updateView', + 'viewIsDescendantOf', + 'PopupMenu', + 'LazyViewManagersEnabled', + 'ViewManagerNames', + 'StyleConstants', + 'AccessibilityEventTypes', + 'UIView', + '__takeSnapshot', + 'takeSnapshot', + 'getViewManagerConfig', + 'measureViewsInRect', + 'blur', + 'focus', + 'genericBubblingEventTypes', + 'genericDirectEventTypes', +]; diff --git a/Libraries/ReactNative/getNativeComponentAttributes.js b/Libraries/ReactNative/getNativeComponentAttributes.js index 64771945f..6a8c54914 100644 --- a/Libraries/ReactNative/getNativeComponentAttributes.js +++ b/Libraries/ReactNative/getNativeComponentAttributes.js @@ -96,7 +96,7 @@ 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) { + if (UIManager.ViewManagerNames || UIManager.LazyViewManagersEnabled) { // Lazy view managers enabled. viewConfig = merge(viewConfig, UIManager.getDefaultEventTypes()); } else { diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK index 262d60c93..9bb553e2e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/BUCK @@ -30,7 +30,7 @@ rn_android_library( react_native_target("java/com/facebook/react/animation:animation"), react_native_target("java/com/facebook/react/bridge:bridge"), react_native_target("java/com/facebook/react/common:common"), - react_native_target("java/com/facebook/react/common:common"), + react_native_target("java/com/facebook/react/config:config"), react_native_target("java/com/facebook/react/module/annotations:annotations"), react_native_target("java/com/facebook/react/modules/core:core"), react_native_target("java/com/facebook/react/modules/i18nmanager:i18nmanager"), diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java index a6aed9343..8e993c193 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java @@ -10,7 +10,7 @@ package com.facebook.react.uimanager; import static com.facebook.systrace.Systrace.TRACE_TAG_REACT_JAVA_BRIDGE; import com.facebook.react.common.MapBuilder; -import com.facebook.systrace.Systrace; +import com.facebook.react.config.ReactFeatureFlags; import com.facebook.systrace.SystraceMessage; import java.util.List; import java.util.Map; @@ -35,7 +35,10 @@ import javax.annotation.Nullable; /* package */ static Map createConstants( UIManagerModule.ViewManagerResolver resolver) { Map constants = UIManagerModuleConstants.getConstants(); - constants.put("ViewManagerNames", resolver.getViewManagerNames()); + if (!ReactFeatureFlags.lazilyLoadViewManagers) { + constants.put("ViewManagerNames", resolver.getViewManagerNames()); + } + constants.put("LazyViewManagersEnabled", true); return constants; }