From 19f6fe170ce920d7183a5620f4e218334c8bac62 Mon Sep 17 00:00:00 2001 From: Eli White Date: Tue, 7 Jan 2020 16:47:19 -0800 Subject: [PATCH] Revert "Revert "Dispatch commands to both UIManagers from both renderers (#17211)" (#17232)" (#17799) * Revert "Revert "Dispatch commands to both UIManagers from both renderers (#17211)" (#17232)" This reverts commit d0fc0ba0a688950b8ab24a89f14888a19efa2444. * Clean up another __DEV__ warning check --- .../react-native-renderer/src/ReactFabric.js | 35 ++++---- .../src/ReactNativeRenderer.js | 20 +++-- .../ReactFabricAndNative-test.internal.js | 88 ++++++++++++++++++- 3 files changed, 116 insertions(+), 27 deletions(-) diff --git a/packages/react-native-renderer/src/ReactFabric.js b/packages/react-native-renderer/src/ReactFabric.js index fd9d06d5104fe..1371067ab0a73 100644 --- a/packages/react-native-renderer/src/ReactFabric.js +++ b/packages/react-native-renderer/src/ReactFabric.js @@ -29,6 +29,9 @@ import {createPortal} from 'shared/ReactPortal'; import {setBatchingImplementation} from 'legacy-events/ReactGenericBatching'; import ReactVersion from 'shared/ReactVersion'; +// Module provided by RN: +import {UIManager} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface'; + import NativeMethodsMixin from './NativeMethodsMixin'; import ReactNativeComponent from './ReactNativeComponent'; import {getClosestInstanceFromNode} from './ReactFabricComponentTree'; @@ -38,8 +41,6 @@ import {LegacyRoot} from 'shared/ReactRootTags'; import ReactSharedInternals from 'shared/ReactSharedInternals'; import getComponentName from 'shared/getComponentName'; -const {dispatchCommand: fabricDispatchCommand} = nativeFabricUIManager; - const ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner; function findHostInstance_DEPRECATED( @@ -162,26 +163,26 @@ const ReactFabric: ReactFabricType = { findNodeHandle, dispatchCommand(handle: any, command: string, args: Array) { - const invalid = - handle._nativeTag == null || handle._internalInstanceHandle == null; - - if (invalid) { + if (handle._nativeTag == null) { if (__DEV__) { - if (invalid) { - console.error( - "dispatchCommand was called with a ref that isn't a " + - 'native component. Use React.forwardRef to get access to the underlying native component', - ); - } + console.error( + "dispatchCommand was called with a ref that isn't a " + + 'native component. Use React.forwardRef to get access to the underlying native component', + ); } + return; } - fabricDispatchCommand( - handle._internalInstanceHandle.stateNode.node, - command, - args, - ); + if (handle._internalInstanceHandle) { + nativeFabricUIManager.dispatchCommand( + handle._internalInstanceHandle.stateNode.node, + command, + args, + ); + } else { + UIManager.dispatchViewManagerCommand(handle._nativeTag, command, args); + } }, render(element: React$Element, containerTag: any, callback: ?Function) { diff --git a/packages/react-native-renderer/src/ReactNativeRenderer.js b/packages/react-native-renderer/src/ReactNativeRenderer.js index c06d1ff267e50..5c5b10fcf1cfa 100644 --- a/packages/react-native-renderer/src/ReactNativeRenderer.js +++ b/packages/react-native-renderer/src/ReactNativeRenderer.js @@ -174,17 +174,23 @@ const ReactNativeRenderer: ReactNativeType = { dispatchCommand(handle: any, command: string, args: Array) { if (handle._nativeTag == null) { if (__DEV__) { - if (handle._nativeTag == null) { - console.error( - "dispatchCommand was called with a ref that isn't a " + - 'native component. Use React.forwardRef to get access to the underlying native component', - ); - } + console.error( + "dispatchCommand was called with a ref that isn't a " + + 'native component. Use React.forwardRef to get access to the underlying native component', + ); } return; } - UIManager.dispatchViewManagerCommand(handle._nativeTag, command, args); + if (handle._internalInstanceHandle) { + nativeFabricUIManager.dispatchCommand( + handle._internalInstanceHandle.stateNode.node, + command, + args, + ); + } else { + UIManager.dispatchViewManagerCommand(handle._nativeTag, command, args); + } }, render(element: React$Element, containerTag: any, callback: ?Function) { diff --git a/packages/react-native-renderer/src/__tests__/ReactFabricAndNative-test.internal.js b/packages/react-native-renderer/src/__tests__/ReactFabricAndNative-test.internal.js index a951395db829e..5efeebfd9211d 100644 --- a/packages/react-native-renderer/src/__tests__/ReactFabricAndNative-test.internal.js +++ b/packages/react-native-renderer/src/__tests__/ReactFabricAndNative-test.internal.js @@ -16,7 +16,7 @@ let ReactNative; let UIManager; let createReactNativeComponentClass; -describe('ReactFabric', () => { +describe('created with ReactFabric called with ReactNative', () => { beforeEach(() => { jest.resetModules(); require('react-native/Libraries/ReactPrivate/InitializeNativeFabricUIManager'); @@ -75,7 +75,7 @@ describe('ReactFabric', () => { }); it('dispatches commands on Fabric nodes with the RN renderer', () => { - UIManager.dispatchViewManagerCommand.mockReset(); + nativeFabricUIManager.dispatchCommand.mockClear(); const View = createReactNativeComponentClass('RCTView', () => ({ validAttributes: {title: true}, uiViewClassName: 'RCTView', @@ -84,13 +84,95 @@ describe('ReactFabric', () => { let ref = React.createRef(); ReactFabric.render(, 11); - expect(UIManager.dispatchViewManagerCommand).not.toBeCalled(); + expect(nativeFabricUIManager.dispatchCommand).not.toBeCalled(); ReactNative.dispatchCommand(ref.current, 'myCommand', [10, 20]); + expect(nativeFabricUIManager.dispatchCommand).toHaveBeenCalledTimes(1); + expect(nativeFabricUIManager.dispatchCommand).toHaveBeenCalledWith( + expect.any(Object), + 'myCommand', + [10, 20], + ); + expect(UIManager.dispatchViewManagerCommand).not.toBeCalled(); + }); +}); + +describe('created with ReactNative called with ReactFabric', () => { + beforeEach(() => { + jest.resetModules(); + require('react-native/Libraries/ReactPrivate/InitializeNativeFabricUIManager'); + ReactFabric = require('react-native-renderer/fabric'); + jest.resetModules(); + UIManager = require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface') + .UIManager; + jest.mock('shared/ReactFeatureFlags', () => + require('shared/forks/ReactFeatureFlags.native-oss'), + ); + ReactNative = require('react-native-renderer'); + + React = require('react'); + createReactNativeComponentClass = require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface') + .ReactNativeViewConfigRegistry.register; + }); + + it('find Paper instances with the Fabric renderer', () => { + const View = createReactNativeComponentClass('RCTView', () => ({ + validAttributes: {title: true}, + uiViewClassName: 'RCTView', + })); + + let ref = React.createRef(); + + class Component extends React.Component { + render() { + return ; + } + } + + ReactNative.render(, 11); + + let instance = ReactFabric.findHostInstance_DEPRECATED(ref.current); + expect(instance._nativeTag).toBe(3); + }); + + it('find Paper nodes with the Fabric renderer', () => { + const View = createReactNativeComponentClass('RCTView', () => ({ + validAttributes: {title: true}, + uiViewClassName: 'RCTView', + })); + + let ref = React.createRef(); + + class Component extends React.Component { + render() { + return ; + } + } + + ReactNative.render(, 11); + + let handle = ReactFabric.findNodeHandle(ref.current); + expect(handle).toBe(3); + }); + + it('dispatches commands on Paper nodes with the Fabric renderer', () => { + UIManager.dispatchViewManagerCommand.mockReset(); + const View = createReactNativeComponentClass('RCTView', () => ({ + validAttributes: {title: true}, + uiViewClassName: 'RCTView', + })); + + let ref = React.createRef(); + + ReactNative.render(, 11); + expect(UIManager.dispatchViewManagerCommand).not.toBeCalled(); + ReactFabric.dispatchCommand(ref.current, 'myCommand', [10, 20]); expect(UIManager.dispatchViewManagerCommand).toHaveBeenCalledTimes(1); expect(UIManager.dispatchViewManagerCommand).toHaveBeenCalledWith( expect.any(Number), 'myCommand', [10, 20], ); + + expect(nativeFabricUIManager.dispatchCommand).not.toBeCalled(); }); });