Fix regression in Java->C++->JS ViewManagers interaction.
Reviewed By: bvaughn Differential Revision: D5953937 fbshipit-source-id: 8bc5dd8a483054ab9830ab653f2a3b41cad6c791
This commit is contained in:
parent
6ba9ad8ece
commit
346af557c3
|
@ -52,6 +52,61 @@ function requireNativeComponent(
|
||||||
componentInterface?: ?ComponentInterface,
|
componentInterface?: ?ComponentInterface,
|
||||||
extraConfig?: ?{nativeOnly?: Object},
|
extraConfig?: ?{nativeOnly?: Object},
|
||||||
): React$ComponentType<any> | string {
|
): React$ComponentType<any> | string {
|
||||||
|
function attachBubblingEventTypes(viewConfig) {
|
||||||
|
if (UIManager.genericBubblingEventTypes) {
|
||||||
|
viewConfig.bubblingEventTypes = merge(
|
||||||
|
viewConfig.bubblingEventTypes,
|
||||||
|
UIManager.genericBubblingEventTypes,
|
||||||
|
);
|
||||||
|
// As genericBubblingEventTypes do not change over time, and there's
|
||||||
|
// merge of all the events happening in Fiber, we need to pass
|
||||||
|
// genericBubblingEventTypes to Fiber only once. Therefore, we can delete
|
||||||
|
// it and forget about it.
|
||||||
|
delete UIManager.genericBubblingEventTypes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function attachDirectEventTypes(viewConfig) {
|
||||||
|
if (UIManager.genericDirectEventTypes) {
|
||||||
|
viewConfig.directEventTypes = merge(
|
||||||
|
viewConfig.directEventTypes,
|
||||||
|
UIManager.genericDirectEventTypes,
|
||||||
|
);
|
||||||
|
// As genericDirectEventTypes do not change over time, and there's merge
|
||||||
|
// of all the events happening in Fiber, we need to pass genericDirectEventTypes
|
||||||
|
// to Fiber only once. Therefore, we can delete it and forget about it.
|
||||||
|
delete 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.
|
// Don't load the ViewConfig from UIManager until it's needed for rendering.
|
||||||
// Lazy-loading this can help avoid Prepack deopts.
|
// Lazy-loading this can help avoid Prepack deopts.
|
||||||
function getViewConfig() {
|
function getViewConfig() {
|
||||||
|
@ -129,6 +184,9 @@ function requireNativeComponent(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
attachBubblingEventTypes(viewConfig);
|
||||||
|
attachDirectEventTypes(viewConfig);
|
||||||
|
|
||||||
// Register this view's event types with the ReactNative renderer.
|
// Register this view's event types with the ReactNative renderer.
|
||||||
// This enables view managers to be initialized lazily, improving perf,
|
// This enables view managers to be initialized lazily, improving perf,
|
||||||
// While also enabling 3rd party components to define custom event types.
|
// While also enabling 3rd party components to define custom event types.
|
||||||
|
|
|
@ -32,6 +32,7 @@ import com.facebook.react.bridge.ReactMethod;
|
||||||
import com.facebook.react.bridge.ReadableArray;
|
import com.facebook.react.bridge.ReadableArray;
|
||||||
import com.facebook.react.bridge.ReadableMap;
|
import com.facebook.react.bridge.ReadableMap;
|
||||||
import com.facebook.react.bridge.WritableMap;
|
import com.facebook.react.bridge.WritableMap;
|
||||||
|
import com.facebook.react.common.MapBuilder;
|
||||||
import com.facebook.react.common.ReactConstants;
|
import com.facebook.react.common.ReactConstants;
|
||||||
import com.facebook.react.module.annotations.ReactModule;
|
import com.facebook.react.module.annotations.ReactModule;
|
||||||
import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener;
|
import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener;
|
||||||
|
@ -114,6 +115,11 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements
|
||||||
|
|
||||||
private int mBatchId = 0;
|
private int mBatchId = 0;
|
||||||
|
|
||||||
|
// Defines if events were already exported to JS. We do not send them more
|
||||||
|
// than once as they are stored and mixed in with Fiber for every ViewManager
|
||||||
|
// on JS side.
|
||||||
|
private boolean mEventsWereSentToJS = false;
|
||||||
|
|
||||||
public UIManagerModule(
|
public UIManagerModule(
|
||||||
ReactApplicationContext reactContext,
|
ReactApplicationContext reactContext,
|
||||||
ViewManagerResolver viewManagerResolver,
|
ViewManagerResolver viewManagerResolver,
|
||||||
|
@ -142,10 +148,8 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements
|
||||||
super(reactContext);
|
super(reactContext);
|
||||||
DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(reactContext);
|
DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(reactContext);
|
||||||
mEventDispatcher = new EventDispatcher(reactContext);
|
mEventDispatcher = new EventDispatcher(reactContext);
|
||||||
mModuleConstants = createConstants(viewManagersList);
|
mCustomDirectEvents = MapBuilder.newHashMap();
|
||||||
mCustomDirectEvents =
|
mModuleConstants = createConstants(viewManagersList, null, mCustomDirectEvents);
|
||||||
(Map<String, Object>) mModuleConstants.get(
|
|
||||||
UIManagerModuleConstantsHelper.CUSTOM_DIRECT_EVENTS_KEY);
|
|
||||||
mUIImplementation =
|
mUIImplementation =
|
||||||
uiImplementationProvider.createUIImplementation(
|
uiImplementationProvider.createUIImplementation(
|
||||||
reactContext,
|
reactContext,
|
||||||
|
@ -214,11 +218,15 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<String, Object> createConstants(List<ViewManager> viewManagers) {
|
private static Map<String, Object> createConstants(
|
||||||
|
List<ViewManager> viewManagers,
|
||||||
|
@Nullable Map<String, Object> customBubblingEvents,
|
||||||
|
@Nullable Map<String, Object> customDirectEvents) {
|
||||||
ReactMarker.logMarker(CREATE_UI_MANAGER_MODULE_CONSTANTS_START);
|
ReactMarker.logMarker(CREATE_UI_MANAGER_MODULE_CONSTANTS_START);
|
||||||
Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "CreateUIManagerConstants");
|
Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "CreateUIManagerConstants");
|
||||||
try {
|
try {
|
||||||
return UIManagerModuleConstantsHelper.createConstants(viewManagers);
|
return UIManagerModuleConstantsHelper.createConstants(
|
||||||
|
viewManagers, customBubblingEvents, customDirectEvents);
|
||||||
} finally {
|
} finally {
|
||||||
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
|
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
|
||||||
ReactMarker.logMarker(CREATE_UI_MANAGER_MODULE_CONSTANTS_END);
|
ReactMarker.logMarker(CREATE_UI_MANAGER_MODULE_CONSTANTS_END);
|
||||||
|
@ -242,11 +250,15 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements
|
||||||
Map<String, Object> viewManagerConstants =
|
Map<String, Object> viewManagerConstants =
|
||||||
UIManagerModuleConstantsHelper.createConstantsForViewManager(
|
UIManagerModuleConstantsHelper.createConstantsForViewManager(
|
||||||
targetView,
|
targetView,
|
||||||
UIManagerModuleConstants.getBubblingEventTypeConstants(),
|
mEventsWereSentToJS ? null : UIManagerModuleConstants.getBubblingEventTypeConstants(),
|
||||||
UIManagerModuleConstants.getDirectEventTypeConstants(),
|
mEventsWereSentToJS ? null : UIManagerModuleConstants.getDirectEventTypeConstants(),
|
||||||
null,
|
null,
|
||||||
mCustomDirectEvents);
|
mCustomDirectEvents);
|
||||||
return viewManagerConstants != null ? Arguments.makeNativeMap(viewManagerConstants) : null;
|
if (viewManagerConstants != null) {
|
||||||
|
mEventsWereSentToJS = true;
|
||||||
|
return Arguments.makeNativeMap(viewManagerConstants);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
} finally {
|
} finally {
|
||||||
SystraceMessage.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
|
SystraceMessage.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,9 +24,6 @@ import javax.annotation.Nullable;
|
||||||
*/
|
*/
|
||||||
/* package */ class UIManagerModuleConstantsHelper {
|
/* package */ class UIManagerModuleConstantsHelper {
|
||||||
|
|
||||||
/* package */ static final String CUSTOM_BUBBLING_EVENTS_KEY = "customBubblingEventTypes";
|
|
||||||
/* package */ static final String CUSTOM_DIRECT_EVENTS_KEY = "customDirectEventTypes";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a lazy discovery enabled version of {@link UIManagerModule} constants. It only
|
* Generates a lazy discovery enabled version of {@link UIManagerModule} constants. It only
|
||||||
* contains a list of view manager names, so that JS side is aware of the managers there are.
|
* contains a list of view manager names, so that JS side is aware of the managers there are.
|
||||||
|
@ -53,22 +50,27 @@ import javax.annotation.Nullable;
|
||||||
* {@link UIManagerModuleConstants}.
|
* {@link UIManagerModuleConstants}.
|
||||||
* TODO(6845124): Create a test for this
|
* TODO(6845124): Create a test for this
|
||||||
*/
|
*/
|
||||||
/* package */ static Map<String, Object> createConstants(List<ViewManager> viewManagers) {
|
/* package */ static Map<String, Object> createConstants(
|
||||||
|
List<ViewManager> viewManagers,
|
||||||
|
@Nullable Map<String, Object> allBubblingEventTypes,
|
||||||
|
@Nullable Map<String, Object> allDirectEventTypes) {
|
||||||
Map<String, Object> constants = UIManagerModuleConstants.getConstants();
|
Map<String, Object> constants = UIManagerModuleConstants.getConstants();
|
||||||
|
|
||||||
// Generic/default event types:
|
// Generic/default event types:
|
||||||
// All view managers are capable of dispatching these events.
|
// All view managers are capable of dispatching these events.
|
||||||
// They will be automatically registered for each view type.
|
// They will be automatically registered with React Fiber.
|
||||||
Map genericBubblingEventTypes = UIManagerModuleConstants.getBubblingEventTypeConstants();
|
Map genericBubblingEventTypes = UIManagerModuleConstants.getBubblingEventTypeConstants();
|
||||||
Map genericDirectEventTypes = UIManagerModuleConstants.getDirectEventTypeConstants();
|
Map genericDirectEventTypes = UIManagerModuleConstants.getDirectEventTypeConstants();
|
||||||
|
|
||||||
// Cumulative event types:
|
// Cumulative event types:
|
||||||
// View manager specific event types are collected as views are loaded.
|
// View manager specific event types are collected as views are loaded.
|
||||||
// This information is used later when events are dispatched.
|
// This information is used later when events are dispatched.
|
||||||
Map allBubblingEventTypes = MapBuilder.newHashMap();
|
if (allBubblingEventTypes != null) {
|
||||||
allBubblingEventTypes.putAll(genericBubblingEventTypes);
|
allBubblingEventTypes.putAll(genericBubblingEventTypes);
|
||||||
Map allDirectEventTypes = MapBuilder.newHashMap();
|
}
|
||||||
allDirectEventTypes.putAll(genericDirectEventTypes);
|
if (allDirectEventTypes != null) {
|
||||||
|
allDirectEventTypes.putAll(genericDirectEventTypes);
|
||||||
|
}
|
||||||
|
|
||||||
for (ViewManager viewManager : viewManagers) {
|
for (ViewManager viewManager : viewManagers) {
|
||||||
final String viewManagerName = viewManager.getName();
|
final String viewManagerName = viewManager.getName();
|
||||||
|
@ -81,8 +83,8 @@ import javax.annotation.Nullable;
|
||||||
try {
|
try {
|
||||||
Map viewManagerConstants = createConstantsForViewManager(
|
Map viewManagerConstants = createConstantsForViewManager(
|
||||||
viewManager,
|
viewManager,
|
||||||
genericBubblingEventTypes,
|
null,
|
||||||
genericDirectEventTypes,
|
null,
|
||||||
allBubblingEventTypes,
|
allBubblingEventTypes,
|
||||||
allDirectEventTypes);
|
allDirectEventTypes);
|
||||||
if (!viewManagerConstants.isEmpty()) {
|
if (!viewManagerConstants.isEmpty()) {
|
||||||
|
@ -93,41 +95,39 @@ import javax.annotation.Nullable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used by https://fburl.com/6nskr82o
|
constants.put("genericBubblingEventTypes", genericBubblingEventTypes);
|
||||||
constants.put(CUSTOM_BUBBLING_EVENTS_KEY, allBubblingEventTypes);
|
constants.put("genericDirectEventTypes", genericDirectEventTypes);
|
||||||
constants.put(CUSTOM_DIRECT_EVENTS_KEY, allDirectEventTypes);
|
|
||||||
return constants;
|
return constants;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */ static Map<String, Object> createConstantsForViewManager(
|
/* package */ static Map<String, Object> createConstantsForViewManager(
|
||||||
ViewManager viewManager,
|
ViewManager viewManager,
|
||||||
Map defaultBubblingEvents,
|
@Nullable Map defaultBubblingEvents,
|
||||||
Map defaultDirectEvents,
|
@Nullable Map defaultDirectEvents,
|
||||||
@Nullable Map cumulativeBubblingEventTypes,
|
@Nullable Map cumulativeBubblingEventTypes,
|
||||||
@Nullable Map cumulativeDirectEventTypes) {
|
@Nullable Map cumulativeDirectEventTypes) {
|
||||||
|
final String BUBBLING_EVENTS_KEY = "bubblingEventTypes";
|
||||||
|
final String DIRECT_EVENTS_KEY = "directEventTypes";
|
||||||
|
|
||||||
Map<String, Object> viewManagerConstants = MapBuilder.newHashMap();
|
Map<String, Object> viewManagerConstants = MapBuilder.newHashMap();
|
||||||
|
|
||||||
Map viewManagerBubblingEvents = viewManager.getExportedCustomBubblingEventTypeConstants();
|
Map viewManagerBubblingEvents = viewManager.getExportedCustomBubblingEventTypeConstants();
|
||||||
if (viewManagerBubblingEvents != null) {
|
if (viewManagerBubblingEvents != null) {
|
||||||
if (cumulativeBubblingEventTypes != null) {
|
recursiveMerge(cumulativeBubblingEventTypes, viewManagerBubblingEvents);
|
||||||
recursiveMerge(cumulativeBubblingEventTypes, viewManagerBubblingEvents);
|
|
||||||
}
|
|
||||||
recursiveMerge(viewManagerBubblingEvents, defaultBubblingEvents);
|
recursiveMerge(viewManagerBubblingEvents, defaultBubblingEvents);
|
||||||
} else {
|
viewManagerConstants.put(BUBBLING_EVENTS_KEY, viewManagerBubblingEvents);
|
||||||
viewManagerBubblingEvents = defaultBubblingEvents;
|
} else if (defaultBubblingEvents != null) {
|
||||||
|
viewManagerConstants.put(BUBBLING_EVENTS_KEY, defaultBubblingEvents);
|
||||||
}
|
}
|
||||||
viewManagerConstants.put("bubblingEventTypes", viewManagerBubblingEvents);
|
|
||||||
|
|
||||||
Map viewManagerDirectEvents = viewManager.getExportedCustomDirectEventTypeConstants();
|
Map viewManagerDirectEvents = viewManager.getExportedCustomDirectEventTypeConstants();
|
||||||
if (viewManagerDirectEvents != null) {
|
if (viewManagerDirectEvents != null) {
|
||||||
if (cumulativeDirectEventTypes != null) {
|
recursiveMerge(cumulativeDirectEventTypes, viewManagerDirectEvents);
|
||||||
recursiveMerge(cumulativeDirectEventTypes, viewManagerBubblingEvents);
|
|
||||||
}
|
|
||||||
recursiveMerge(viewManagerDirectEvents, defaultDirectEvents);
|
recursiveMerge(viewManagerDirectEvents, defaultDirectEvents);
|
||||||
} else {
|
viewManagerConstants.put(DIRECT_EVENTS_KEY, viewManagerDirectEvents);
|
||||||
viewManagerDirectEvents = defaultDirectEvents;
|
} else if (defaultDirectEvents != null) {
|
||||||
|
viewManagerConstants.put(DIRECT_EVENTS_KEY, defaultDirectEvents);
|
||||||
}
|
}
|
||||||
viewManagerConstants.put("directEventTypes", viewManagerDirectEvents);
|
|
||||||
|
|
||||||
Map customViewConstants = viewManager.getExportedViewConstants();
|
Map customViewConstants = viewManager.getExportedViewConstants();
|
||||||
if (customViewConstants != null) {
|
if (customViewConstants != null) {
|
||||||
|
@ -148,7 +148,11 @@ import javax.annotation.Nullable;
|
||||||
/**
|
/**
|
||||||
* Merges {@param source} map into {@param dest} map recursively
|
* Merges {@param source} map into {@param dest} map recursively
|
||||||
*/
|
*/
|
||||||
private static void recursiveMerge(Map dest, Map source) {
|
private static void recursiveMerge(@Nullable Map dest, @Nullable Map source) {
|
||||||
|
if (dest == null || source == null || source.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (Object key : source.keySet()) {
|
for (Object key : source.keySet()) {
|
||||||
Object sourceValue = source.get(key);
|
Object sourceValue = source.get(key);
|
||||||
Object destValue = dest.get(key);
|
Object destValue = dest.get(key);
|
||||||
|
|
Loading…
Reference in New Issue