Dispatch commands to both UIManagers from both renderers (#17211)
* Dispatch commands to both UIManagers from both renderers * Merge test files
Eli White committed
Oct 29, 2019 at 18:16 UTC
8eee0eb01ce3ead0f51ade75fdcf062a748d57a7
3 files changed
+88
-16
packages/react-native-renderer/src/ReactFabric.js
+14
-12
@@ -29,6 +29,9 @@ import {createPortal} from 'shared/ReactPortal';
29
import {setBatchingImplementation} from 'legacy-events/ReactGenericBatching';
30
import ReactVersion from 'shared/ReactVersion';
31
32
+// Module provided by RN:
33
+import {UIManager} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
34
+
35
import NativeMethodsMixin from './NativeMethodsMixin';
36
import ReactNativeComponent from './ReactNativeComponent';
37
import {getClosestInstanceFromNode} from './ReactFabricComponentTree';
@@ -39,8 +42,6 @@ import ReactSharedInternals from 'shared/ReactSharedInternals';
42
import getComponentName from 'shared/getComponentName';
43
import warningWithoutStack from 'shared/warningWithoutStack';
44
42
-const {dispatchCommand: fabricDispatchCommand} = nativeFabricUIManager;
43
-
45
const ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;
46
47
function findNodeHandle(componentOrHandle: any): ?number {
@@ -110,23 +111,24 @@ const ReactFabric: ReactFabricType = {
111
findNodeHandle,
112
113
dispatchCommand(handle: any, command: string, args: Array<any>) {
113
- const invalid =
114
- handle._nativeTag == null || handle._internalInstanceHandle == null;
115
-
116
- if (invalid) {
114
+ if (handle._nativeTag == null) {
115
warningWithoutStack(
118
- !invalid,
116
+ handle._nativeTag != null,
117
"dispatchCommand was called with a ref that isn't a " +
118
'native component. Use React.forwardRef to get access to the underlying native component',
119
);
120
return;
121
}
122
125
- fabricDispatchCommand(
126
- handle._internalInstanceHandle.stateNode.node,
127
- command,
128
- args,
129
- );
123
+ if (handle._internalInstanceHandle) {
124
+ nativeFabricUIManager.dispatchCommand(
125
+ handle._internalInstanceHandle.stateNode.node,
126
+ command,
127
+ args,
128
+ );
129
+ } else {
130
+ UIManager.dispatchViewManagerCommand(handle._nativeTag, command, args);
131
+ }
132
},
133
134
render(element: React$Element<any>, containerTag: any, callback: ?Function) {
packages/react-native-renderer/src/ReactNativeRenderer.js
+9
-1
@@ -129,7 +129,15 @@ const ReactNativeRenderer: ReactNativeType = {
129
return;
130
}
131
132
- UIManager.dispatchViewManagerCommand(handle._nativeTag, command, args);
132
+ if (handle._internalInstanceHandle) {
133
+ nativeFabricUIManager.dispatchCommand(
134
+ handle._internalInstanceHandle.stateNode.node,
135
+ command,
136
+ args,
137
+ );
138
+ } else {
139
+ UIManager.dispatchViewManagerCommand(handle._nativeTag, command, args);
140
+ }
141
},
142
143
render(element: React$Element<any>, containerTag: any, callback: ?Function) {
packages/react-native-renderer/src/__tests__/ReactFabricAndNative-test.internal.js
+65
-3
@@ -16,7 +16,7 @@ let ReactNative;
16
let UIManager;
17
let createReactNativeComponentClass;
18
19
-describe('ReactFabric', () => {
19
+describe('created with ReactFabric called with ReactNative', () => {
20
beforeEach(() => {
21
jest.resetModules();
22
require('react-native/Libraries/ReactPrivate/InitializeNativeFabricUIManager');
@@ -55,7 +55,7 @@ describe('ReactFabric', () => {
55
});
56
57
it('dispatches commands on Fabric nodes with the RN renderer', () => {
58
- UIManager.dispatchViewManagerCommand.mockReset();
58
+ nativeFabricUIManager.dispatchCommand.mockClear();
59
const View = createReactNativeComponentClass('RCTView', () => ({
60
validAttributes: {title: true},
61
uiViewClassName: 'RCTView',
@@ -64,13 +64,75 @@ describe('ReactFabric', () => {
64
let ref = React.createRef();
65
66
ReactFabric.render(<View title="bar" ref={ref} />, 11);
67
- expect(UIManager.dispatchViewManagerCommand).not.toBeCalled();
67
+ expect(nativeFabricUIManager.dispatchCommand).not.toBeCalled();
68
ReactNative.dispatchCommand(ref.current, 'myCommand', [10, 20]);
69
+ expect(nativeFabricUIManager.dispatchCommand).toHaveBeenCalledTimes(1);
70
+ expect(nativeFabricUIManager.dispatchCommand).toHaveBeenCalledWith(
71
+ expect.any(Object),
72
+ 'myCommand',
73
+ [10, 20],
74
+ );
75
+ expect(UIManager.dispatchViewManagerCommand).not.toBeCalled();
76
+ });
77
+});
78
+
79
+describe('created with ReactNative called with ReactFabric', () => {
80
+ beforeEach(() => {
81
+ jest.resetModules();
82
+ require('react-native/Libraries/ReactPrivate/InitializeNativeFabricUIManager');
83
+ ReactFabric = require('react-native-renderer/fabric');
84
+ jest.resetModules();
85
+ UIManager = require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface')
86
+ .UIManager;
87
+ jest.mock('shared/ReactFeatureFlags', () =>
88
+ require('shared/forks/ReactFeatureFlags.native-oss'),
89
+ );
90
+ ReactNative = require('react-native-renderer');
91
+
92
+ React = require('react');
93
+ createReactNativeComponentClass = require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface')
94
+ .ReactNativeViewConfigRegistry.register;
95
+ });
96
+
97
+ it('find Paper nodes with the Fabric renderer', () => {
98
+ const View = createReactNativeComponentClass('RCTView', () => ({
99
+ validAttributes: {title: true},
100
+ uiViewClassName: 'RCTView',
101
+ }));
102
+
103
+ let ref = React.createRef();
104
+
105
+ class Component extends React.Component {
106
+ render() {
107
+ return <View title="foo" />;
108
+ }
109
+ }
110
+
111
+ ReactNative.render(<Component ref={ref} />, 11);
112
+
113
+ let handle = ReactFabric.findNodeHandle(ref.current);
114
+ expect(handle).toBe(3);
115
+ });
116
+
117
+ it('dispatches commands on Paper nodes with the Fabric renderer', () => {
118
+ UIManager.dispatchViewManagerCommand.mockReset();
119
+ const View = createReactNativeComponentClass('RCTView', () => ({
120
+ validAttributes: {title: true},
121
+ uiViewClassName: 'RCTView',
122
+ }));
123
+
124
+ let ref = React.createRef();
125
+
126
+ ReactNative.render(<View title="bar" ref={ref} />, 11);
127
+ expect(UIManager.dispatchViewManagerCommand).not.toBeCalled();
128
+ ReactFabric.dispatchCommand(ref.current, 'myCommand', [10, 20]);
129
expect(UIManager.dispatchViewManagerCommand).toHaveBeenCalledTimes(1);
130
expect(UIManager.dispatchViewManagerCommand).toHaveBeenCalledWith(
131
expect.any(Number),
132
'myCommand',
133
[10, 20],
134
);
135
+
136
+ expect(nativeFabricUIManager.dispatchCommand).not.toBeCalled();
137
});
138
});