@samitouri / QOS-React-1 / commits / d66fa02a30

fix: use public instance in Fiber renderer and expose it from getInspectorDataForViewAtPoint (#31068)

React DevTools no longer operates with just Fibers, it now builds its own Shadow Tree, which represents the tree on the Host (Fabric on Native, DOM on Web). We have to keep track of public instances for a select-to-inspect feature. We've recently changed this logic in https://github.com/facebook/react/pull/30831, and looks like we've been incorrectly getting a public instance for Fabric case. Not only this, turns out that all `getInspectorData...` APIs are returning Fibers, and not public instances. I have to expose it, so that React DevTools can correctly identify the element, which was selected. Changes for React Native are in [D63421463](https://www.internalfb.com/diff/D63421463)

Ruslan Lesiutin committed Sep 26, 2024 at 10:17 UTC d66fa02a303fc53d901bdb0d7bbdaec3e6774b19
3 files changed +26 -7
packages/react-devtools-shared/src/backend/fiber/renderer.js
+21 -7
@@ -763,16 +763,30 @@ const hostResourceToDevToolsInstanceMap: Map<
763 Set<DevToolsInstance>,
764 > = new Map();
765
766 +// Ideally, this should be injected from Reconciler config
767 function getPublicInstance(instance: HostInstance): HostInstance {
768 // Typically the PublicInstance and HostInstance is the same thing but not in Fabric.
769 // So we need to detect this and use that as the public instance.
769 - return typeof instance === 'object' &&
770 - instance !== null &&
771 - typeof instance.canonical === 'object'
772 - ? (instance.canonical: any)
773 - : typeof instance._nativeTag === 'number'
774 - ? instance._nativeTag
775 - : instance;
770 +
771 + // React Native. Modern. Fabric.
772 + if (typeof instance === 'object' && instance !== null) {
773 + if (typeof instance.canonical === 'object' && instance.canonical !== null) {
774 + if (
775 + typeof instance.canonical.publicInstance === 'object' &&
776 + instance.canonical.publicInstance !== null
777 + ) {
778 + return instance.canonical.publicInstance;
779 + }
780 + }
781 +
782 + // React Native. Legacy. Paper.
783 + if (typeof instance._nativeTag === 'number') {
784 + return instance._nativeTag;
785 + }
786 + }
787 +
788 + // React Web. Usually a DOM element.
789 + return instance;
790 }
791
792 function aquireHostInstance(
packages/react-native-renderer/src/ReactNativeFiberInspector.js
+4
@@ -209,6 +209,8 @@ function getInspectorDataForViewAtPoint(
209
210 closestInstance =
211 internalInstanceHandle.stateNode.canonical.internalInstanceHandle;
212 + const closestPublicInstance =
213 + internalInstanceHandle.stateNode.canonical.publicInstance;
214
215 // Note: this is deprecated and we want to remove it ASAP. Keeping it here for React DevTools compatibility for now.
216 const nativeViewTag =
@@ -224,6 +226,7 @@ function getInspectorDataForViewAtPoint(
226 pointerY: locationY,
227 frame: {left: pageX, top: pageY, width, height},
228 touchedViewTag: nativeViewTag,
229 + closestPublicInstance,
230 });
231 },
232 );
@@ -243,6 +246,7 @@ function getInspectorDataForViewAtPoint(
246 pointerY: locationY,
247 frame: {left, top, width, height},
248 touchedViewTag: nativeViewTag,
249 + closestPublicInstance: nativeViewTag,
250 });
251 },
252 );
packages/react-native-renderer/src/ReactNativeTypes.js
+1
@@ -179,6 +179,7 @@ export type TouchedViewDataAtPoint = $ReadOnly<{
179 width: number,
180 height: number,
181 }>,
182 + closestPublicInstance?: PublicInstance,
183 ...InspectorData,
184 }>;
185