diff --git a/packages/react-native-renderer/src/ReactFabric.js b/packages/react-native-renderer/src/ReactFabric.js
index e4e663de728ab..0634921b68fec 100644
--- a/packages/react-native-renderer/src/ReactFabric.js
+++ b/packages/react-native-renderer/src/ReactFabric.js
@@ -20,7 +20,7 @@ import ReactVersion from 'shared/ReactVersion';
import NativeMethodsMixin from './NativeMethodsMixin';
import ReactNativeComponent from './ReactNativeComponent';
-import * as ReactNativeComponentTree from './ReactNativeComponentTree';
+import * as ReactFabricComponentTree from './ReactFabricComponentTree';
import {getInspectorDataForViewTag} from './ReactNativeFiberInspector';
import {ReactCurrentOwner} from 'shared/ReactGlobalSharedState';
@@ -120,7 +120,7 @@ const ReactFabric: ReactFabricType = {
};
ReactFabricRenderer.injectIntoDevTools({
- findFiberByHostInstance: ReactNativeComponentTree.getClosestInstanceFromNode,
+ findFiberByHostInstance: ReactFabricComponentTree.getClosestInstanceFromNode,
getInspectorDataForViewTag: getInspectorDataForViewTag,
bundleType: __DEV__ ? 1 : 0,
version: ReactVersion,
diff --git a/packages/react-native-renderer/src/ReactFabricComponentTree.js b/packages/react-native-renderer/src/ReactFabricComponentTree.js
new file mode 100644
index 0000000000000..23f5ce9b950ea
--- /dev/null
+++ b/packages/react-native-renderer/src/ReactFabricComponentTree.js
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2013-present, Facebook, Inc.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+import invariant from 'fbjs/lib/invariant';
+
+function getInstanceFromInstance(instanceHandle) {
+ return instanceHandle;
+}
+
+function getTagFromInstance(inst) {
+ let tag = inst.stateNode.canonical._nativeTag;
+ invariant(tag, 'All native instances should have a tag.');
+ return tag;
+}
+
+export {
+ getInstanceFromInstance as getClosestInstanceFromNode,
+ getInstanceFromInstance as getInstanceFromNode,
+ getTagFromInstance as getNodeFromInstance,
+};
+
+export function getFiberCurrentPropsFromNode(inst) {
+ return inst.canonical.currentProps;
+}
diff --git a/packages/react-native-renderer/src/ReactFabricHostConfig.js b/packages/react-native-renderer/src/ReactFabricHostConfig.js
index 321b86753e8f8..ef4525d8e5cc7 100644
--- a/packages/react-native-renderer/src/ReactFabricHostConfig.js
+++ b/packages/react-native-renderer/src/ReactFabricHostConfig.js
@@ -293,6 +293,8 @@ export function prepareUpdate(
);
// TODO: If the event handlers have changed, we need to update the current props
// in the commit phase but there is no host config hook to do it yet.
+ // So instead we hack it by updating it in the render phase.
+ instance.canonical.currentProps = newProps;
return updatePayload;
}
diff --git a/packages/react-native-renderer/src/ReactFabricInjection.js b/packages/react-native-renderer/src/ReactFabricInjection.js
index eb4c2bca3f18c..a3e766b47e636 100644
--- a/packages/react-native-renderer/src/ReactFabricInjection.js
+++ b/packages/react-native-renderer/src/ReactFabricInjection.js
@@ -9,15 +9,7 @@
import './ReactNativeInjectionShared';
-// TODO: The event emitter registration is interfering with the existing
-// ReactNative renderer. So disable it for Fabric for now.
+import * as ReactFabricComponentTree from './ReactFabricComponentTree';
+import * as EventPluginUtils from 'events/EventPluginUtils';
-// import * as ReactNativeEventEmitter from './ReactNativeEventEmitter';
-
-// Module provided by RN:
-// import RCTEventEmitter from 'RCTEventEmitter';
-
-/**
- * Register the event emitter with the native bridge
- */
-// RCTEventEmitter.register(ReactNativeEventEmitter);
+EventPluginUtils.injection.injectComponentTree(ReactFabricComponentTree);
diff --git a/packages/react-native-renderer/src/ReactNativeComponentTree.js b/packages/react-native-renderer/src/ReactNativeComponentTree.js
index 6123dc192837e..32554cd0bc7c2 100644
--- a/packages/react-native-renderer/src/ReactNativeComponentTree.js
+++ b/packages/react-native-renderer/src/ReactNativeComponentTree.js
@@ -20,12 +20,7 @@ export function uncacheFiberNode(tag) {
}
function getInstanceFromTag(tag) {
- if (typeof tag === 'number') {
- return instanceCache[tag] || null;
- } else {
- // Fabric will invoke event emitters on a direct fiber reference
- return tag;
- }
+ return instanceCache[tag] || null;
}
function getTagFromInstance(inst) {
diff --git a/packages/react-native-renderer/src/ReactNativeInjection.js b/packages/react-native-renderer/src/ReactNativeInjection.js
index df5a468cd12d3..801304cf0d83a 100644
--- a/packages/react-native-renderer/src/ReactNativeInjection.js
+++ b/packages/react-native-renderer/src/ReactNativeInjection.js
@@ -9,6 +9,8 @@
import './ReactNativeInjectionShared';
+import * as ReactNativeComponentTree from './ReactNativeComponentTree';
+import * as EventPluginUtils from 'events/EventPluginUtils';
import * as ReactNativeEventEmitter from './ReactNativeEventEmitter';
// Module provided by RN:
@@ -18,3 +20,5 @@ import RCTEventEmitter from 'RCTEventEmitter';
* Register the event emitter with the native bridge
*/
RCTEventEmitter.register(ReactNativeEventEmitter);
+
+EventPluginUtils.injection.injectComponentTree(ReactNativeComponentTree);
diff --git a/packages/react-native-renderer/src/ReactNativeInjectionShared.js b/packages/react-native-renderer/src/ReactNativeInjectionShared.js
index cc35fdebe961a..be0f25a4d3e6d 100644
--- a/packages/react-native-renderer/src/ReactNativeInjectionShared.js
+++ b/packages/react-native-renderer/src/ReactNativeInjectionShared.js
@@ -17,11 +17,9 @@
import 'InitializeCore';
import * as EventPluginHub from 'events/EventPluginHub';
-import * as EventPluginUtils from 'events/EventPluginUtils';
import ResponderEventPlugin from 'events/ResponderEventPlugin';
import ReactNativeBridgeEventPlugin from './ReactNativeBridgeEventPlugin';
-import * as ReactNativeComponentTree from './ReactNativeComponentTree';
import ReactNativeEventPluginOrder from './ReactNativeEventPluginOrder';
import ReactNativeGlobalResponderHandler from './ReactNativeGlobalResponderHandler';
@@ -29,7 +27,6 @@ import ReactNativeGlobalResponderHandler from './ReactNativeGlobalResponderHandl
* Inject module for resolving DOM hierarchy and plugin ordering.
*/
EventPluginHub.injection.injectEventPluginOrder(ReactNativeEventPluginOrder);
-EventPluginUtils.injection.injectComponentTree(ReactNativeComponentTree);
ResponderEventPlugin.injection.injectGlobalResponderHandler(
ReactNativeGlobalResponderHandler,
diff --git a/packages/react-native-renderer/src/__tests__/ReactFabric-test.internal.js b/packages/react-native-renderer/src/__tests__/ReactFabric-test.internal.js
index d01a5a26f35a7..fda50ecb78b68 100644
--- a/packages/react-native-renderer/src/__tests__/ReactFabric-test.internal.js
+++ b/packages/react-native-renderer/src/__tests__/ReactFabric-test.internal.js
@@ -352,4 +352,49 @@ describe('ReactFabric', () => {
11,
);
});
+
+ it('dispatches events to the last committed props', () => {
+ const View = createReactNativeComponentClass('RCTView', () => ({
+ validAttributes: {},
+ uiViewClassName: 'RCTView',
+ directEventTypes: {
+ topTouchStart: {
+ registrationName: 'onTouchStart',
+ },
+ },
+ }));
+
+ const touchStart = jest.fn();
+ const touchStart2 = jest.fn();
+
+ ReactFabric.render(, 11);
+
+ expect(FabricUIManager.createNode.mock.calls.length).toBe(1);
+ expect(FabricUIManager.registerEventHandler.mock.calls.length).toBe(1);
+
+ let [, , , , instanceHandle] = FabricUIManager.createNode.mock.calls[0];
+ let [dispatchEvent] = FabricUIManager.registerEventHandler.mock.calls[0];
+
+ let touchEvent = {
+ touches: [],
+ changedTouches: [],
+ };
+
+ expect(touchStart).not.toBeCalled();
+
+ dispatchEvent(instanceHandle, 'topTouchStart', touchEvent);
+
+ expect(touchStart).toBeCalled();
+ expect(touchStart2).not.toBeCalled();
+
+ ReactFabric.render(, 11);
+
+ // Intentionally dispatch to the same instanceHandle again.
+ dispatchEvent(instanceHandle, 'topTouchStart', touchEvent);
+
+ // The current semantics dictate that we always dispatch to the last committed
+ // props even though the actual scheduling of the event could have happened earlier.
+ // This could change in the future.
+ expect(touchStart2).toBeCalled();
+ });
});