Implement public instances for text nodes in Fabric (#26516)

## Summary

This adds the ability to create public instances for text nodes in
Fabric. The implementation for the public instances lives in React
Native (as it does for host components after #26437). The logic here
just handles their lazy instantiation when requested via
`getPublicInstanceFromInternalInstanceHandle`, which is called by Fabric
with information coming from the shadow tree.

It's important that the creation of public instances for text nodes is
done lazily to avoid regressing memory usage when unused. Instances for
text nodes are left intact if the public instance is never accessed.

This is necessary to implement access to text nodes in React Native as
explained in
https://github.com/react-native-community/discussions-and-proposals/pull/607

## How did you test this change?

Added unit tests (also fixed a test that was only testing the logic in a
mock :S).

DiffTrain build for commit https://github.com/facebook/react/commit/0700dd50bda98f5ee86f2e3adfe5e9906ed1e8e3.
This commit is contained in:
rubennorte
2023-04-04 13:48:27 +00:00
parent 6b19def69f
commit 08375e667c
14 changed files with 109 additions and 73 deletions
@@ -23882,7 +23882,7 @@ function createFiberRoot(
return root;
}
var ReactVersion = "18.3.0-next-4a1cc2ddd-20230403";
var ReactVersion = "18.3.0-next-0700dd50b-20230404";
// Might add PROFILE later.
@@ -8683,7 +8683,7 @@ var devToolsConfig$jscomp$inline_1028 = {
throw Error("TestRenderer does not support findFiberByHostInstance()");
},
bundleType: 0,
version: "18.3.0-next-4a1cc2ddd-20230403",
version: "18.3.0-next-0700dd50b-20230404",
rendererPackageName: "react-test-renderer"
};
var internals$jscomp$inline_1220 = {
@@ -8714,7 +8714,7 @@ var internals$jscomp$inline_1220 = {
scheduleRoot: null,
setRefreshHandler: null,
getCurrentFiber: null,
reconcilerVersion: "18.3.0-next-4a1cc2ddd-20230403"
reconcilerVersion: "18.3.0-next-0700dd50b-20230404"
};
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
var hook$jscomp$inline_1221 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
@@ -9108,7 +9108,7 @@ var devToolsConfig$jscomp$inline_1070 = {
throw Error("TestRenderer does not support findFiberByHostInstance()");
},
bundleType: 0,
version: "18.3.0-next-4a1cc2ddd-20230403",
version: "18.3.0-next-0700dd50b-20230404",
rendererPackageName: "react-test-renderer"
};
var internals$jscomp$inline_1261 = {
@@ -9139,7 +9139,7 @@ var internals$jscomp$inline_1261 = {
scheduleRoot: null,
setRefreshHandler: null,
getCurrentFiber: null,
reconcilerVersion: "18.3.0-next-4a1cc2ddd-20230403"
reconcilerVersion: "18.3.0-next-0700dd50b-20230404"
};
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
var hook$jscomp$inline_1262 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
@@ -27,7 +27,7 @@ if (
}
"use strict";
var ReactVersion = "18.3.0-next-4a1cc2ddd-20230403";
var ReactVersion = "18.3.0-next-0700dd50b-20230404";
// ATTENTION
// When adding new symbols to this file,
@@ -639,4 +639,4 @@ exports.useSyncExternalStore = function (
);
};
exports.useTransition = useTransition;
exports.version = "18.3.0-next-4a1cc2ddd-20230403";
exports.version = "18.3.0-next-0700dd50b-20230404";
@@ -642,7 +642,7 @@ exports.useSyncExternalStore = function (
);
};
exports.useTransition = useTransition;
exports.version = "18.3.0-next-4a1cc2ddd-20230403";
exports.version = "18.3.0-next-0700dd50b-20230404";
/* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */
if (
@@ -1 +1 @@
4a1cc2ddd035f5c269e82ab6f7686e2e60d3b3ea
0700dd50bda98f5ee86f2e3adfe5e9906ed1e8e3
@@ -4985,7 +4985,24 @@ function getPublicInstance(instance) {
return null;
}
function getPublicTextInstance(textInstance, internalInstanceHandle) {
if (textInstance.publicInstance == null) {
textInstance.publicInstance =
ReactNativePrivateInterface.createPublicTextInstance(
internalInstanceHandle
);
}
return textInstance.publicInstance;
}
function getPublicInstanceFromInternalInstanceHandle(internalInstanceHandle) {
if (internalInstanceHandle.tag === HostText) {
var textInstance = internalInstanceHandle.stateNode;
return getPublicTextInstance(textInstance, internalInstanceHandle);
}
var instance = internalInstanceHandle.stateNode;
return getPublicInstance(instance);
}
@@ -27158,7 +27175,7 @@ function createFiberRoot(
return root;
}
var ReactVersion = "18.3.0-next-4a1cc2ddd-20230403";
var ReactVersion = "18.3.0-next-0700dd50b-20230404";
function createPortal$1(
children,
@@ -940,7 +940,7 @@ eventPluginOrder = Array.prototype.slice.call([
"ReactNativeBridgeEventPlugin"
]);
recomputePluginOrdering();
var injectedNamesToPlugins$jscomp$inline_243 = {
var injectedNamesToPlugins$jscomp$inline_244 = {
ResponderEventPlugin: ResponderEventPlugin,
ReactNativeBridgeEventPlugin: {
eventTypes: {},
@@ -986,32 +986,32 @@ var injectedNamesToPlugins$jscomp$inline_243 = {
}
}
},
isOrderingDirty$jscomp$inline_244 = !1,
pluginName$jscomp$inline_245;
for (pluginName$jscomp$inline_245 in injectedNamesToPlugins$jscomp$inline_243)
isOrderingDirty$jscomp$inline_245 = !1,
pluginName$jscomp$inline_246;
for (pluginName$jscomp$inline_246 in injectedNamesToPlugins$jscomp$inline_244)
if (
injectedNamesToPlugins$jscomp$inline_243.hasOwnProperty(
pluginName$jscomp$inline_245
injectedNamesToPlugins$jscomp$inline_244.hasOwnProperty(
pluginName$jscomp$inline_246
)
) {
var pluginModule$jscomp$inline_246 =
injectedNamesToPlugins$jscomp$inline_243[pluginName$jscomp$inline_245];
var pluginModule$jscomp$inline_247 =
injectedNamesToPlugins$jscomp$inline_244[pluginName$jscomp$inline_246];
if (
!namesToPlugins.hasOwnProperty(pluginName$jscomp$inline_245) ||
namesToPlugins[pluginName$jscomp$inline_245] !==
pluginModule$jscomp$inline_246
!namesToPlugins.hasOwnProperty(pluginName$jscomp$inline_246) ||
namesToPlugins[pluginName$jscomp$inline_246] !==
pluginModule$jscomp$inline_247
) {
if (namesToPlugins[pluginName$jscomp$inline_245])
if (namesToPlugins[pluginName$jscomp$inline_246])
throw Error(
"EventPluginRegistry: Cannot inject two different event plugins using the same name, `" +
(pluginName$jscomp$inline_245 + "`.")
(pluginName$jscomp$inline_246 + "`.")
);
namesToPlugins[pluginName$jscomp$inline_245] =
pluginModule$jscomp$inline_246;
isOrderingDirty$jscomp$inline_244 = !0;
namesToPlugins[pluginName$jscomp$inline_246] =
pluginModule$jscomp$inline_247;
isOrderingDirty$jscomp$inline_245 = !0;
}
}
isOrderingDirty$jscomp$inline_244 && recomputePluginOrdering();
isOrderingDirty$jscomp$inline_245 && recomputePluginOrdering();
var emptyObject$1 = {},
removedKeys = null,
removedKeyCount = 0,
@@ -9551,10 +9551,10 @@ batchedUpdatesImpl = function (fn, a) {
}
};
var roots = new Map(),
devToolsConfig$jscomp$inline_1048 = {
devToolsConfig$jscomp$inline_1052 = {
findFiberByHostInstance: getInstanceFromNode,
bundleType: 0,
version: "18.3.0-next-4a1cc2ddd-20230403",
version: "18.3.0-next-0700dd50b-20230404",
rendererPackageName: "react-native-renderer",
rendererConfig: {
getInspectorDataForViewTag: function () {
@@ -9569,11 +9569,11 @@ var roots = new Map(),
}.bind(null, findNodeHandle)
}
};
var internals$jscomp$inline_1293 = {
bundleType: devToolsConfig$jscomp$inline_1048.bundleType,
version: devToolsConfig$jscomp$inline_1048.version,
rendererPackageName: devToolsConfig$jscomp$inline_1048.rendererPackageName,
rendererConfig: devToolsConfig$jscomp$inline_1048.rendererConfig,
var internals$jscomp$inline_1297 = {
bundleType: devToolsConfig$jscomp$inline_1052.bundleType,
version: devToolsConfig$jscomp$inline_1052.version,
rendererPackageName: devToolsConfig$jscomp$inline_1052.rendererPackageName,
rendererConfig: devToolsConfig$jscomp$inline_1052.rendererConfig,
overrideHookState: null,
overrideHookStateDeletePath: null,
overrideHookStateRenamePath: null,
@@ -9589,26 +9589,26 @@ var internals$jscomp$inline_1293 = {
return null === fiber ? null : fiber.stateNode;
},
findFiberByHostInstance:
devToolsConfig$jscomp$inline_1048.findFiberByHostInstance ||
devToolsConfig$jscomp$inline_1052.findFiberByHostInstance ||
emptyFindFiberByHostInstance,
findHostInstancesForRefresh: null,
scheduleRefresh: null,
scheduleRoot: null,
setRefreshHandler: null,
getCurrentFiber: null,
reconcilerVersion: "18.3.0-next-4a1cc2ddd-20230403"
reconcilerVersion: "18.3.0-next-0700dd50b-20230404"
};
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
var hook$jscomp$inline_1294 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
var hook$jscomp$inline_1298 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
if (
!hook$jscomp$inline_1294.isDisabled &&
hook$jscomp$inline_1294.supportsFiber
!hook$jscomp$inline_1298.isDisabled &&
hook$jscomp$inline_1298.supportsFiber
)
try {
(rendererID = hook$jscomp$inline_1294.inject(
internals$jscomp$inline_1293
(rendererID = hook$jscomp$inline_1298.inject(
internals$jscomp$inline_1297
)),
(injectedHook = hook$jscomp$inline_1294);
(injectedHook = hook$jscomp$inline_1298);
} catch (err) {}
}
exports.createPortal = function (children, containerTag) {
@@ -9687,6 +9687,15 @@ exports.getNodeFromInternalInstanceHandle = function (internalInstanceHandle) {
exports.getPublicInstanceFromInternalInstanceHandle = function (
internalInstanceHandle
) {
if (6 === internalInstanceHandle.tag) {
var textInstance = internalInstanceHandle.stateNode;
null == textInstance.publicInstance &&
(textInstance.publicInstance =
ReactNativePrivateInterface.createPublicTextInstance(
internalInstanceHandle
));
return textInstance.publicInstance;
}
return getPublicInstance(internalInstanceHandle.stateNode);
};
exports.render = function (element, containerTag, callback, concurrentRoot) {
@@ -951,7 +951,7 @@ eventPluginOrder = Array.prototype.slice.call([
"ReactNativeBridgeEventPlugin"
]);
recomputePluginOrdering();
var injectedNamesToPlugins$jscomp$inline_259 = {
var injectedNamesToPlugins$jscomp$inline_260 = {
ResponderEventPlugin: ResponderEventPlugin,
ReactNativeBridgeEventPlugin: {
eventTypes: {},
@@ -997,32 +997,32 @@ var injectedNamesToPlugins$jscomp$inline_259 = {
}
}
},
isOrderingDirty$jscomp$inline_260 = !1,
pluginName$jscomp$inline_261;
for (pluginName$jscomp$inline_261 in injectedNamesToPlugins$jscomp$inline_259)
isOrderingDirty$jscomp$inline_261 = !1,
pluginName$jscomp$inline_262;
for (pluginName$jscomp$inline_262 in injectedNamesToPlugins$jscomp$inline_260)
if (
injectedNamesToPlugins$jscomp$inline_259.hasOwnProperty(
pluginName$jscomp$inline_261
injectedNamesToPlugins$jscomp$inline_260.hasOwnProperty(
pluginName$jscomp$inline_262
)
) {
var pluginModule$jscomp$inline_262 =
injectedNamesToPlugins$jscomp$inline_259[pluginName$jscomp$inline_261];
var pluginModule$jscomp$inline_263 =
injectedNamesToPlugins$jscomp$inline_260[pluginName$jscomp$inline_262];
if (
!namesToPlugins.hasOwnProperty(pluginName$jscomp$inline_261) ||
namesToPlugins[pluginName$jscomp$inline_261] !==
pluginModule$jscomp$inline_262
!namesToPlugins.hasOwnProperty(pluginName$jscomp$inline_262) ||
namesToPlugins[pluginName$jscomp$inline_262] !==
pluginModule$jscomp$inline_263
) {
if (namesToPlugins[pluginName$jscomp$inline_261])
if (namesToPlugins[pluginName$jscomp$inline_262])
throw Error(
"EventPluginRegistry: Cannot inject two different event plugins using the same name, `" +
(pluginName$jscomp$inline_261 + "`.")
(pluginName$jscomp$inline_262 + "`.")
);
namesToPlugins[pluginName$jscomp$inline_261] =
pluginModule$jscomp$inline_262;
isOrderingDirty$jscomp$inline_260 = !0;
namesToPlugins[pluginName$jscomp$inline_262] =
pluginModule$jscomp$inline_263;
isOrderingDirty$jscomp$inline_261 = !0;
}
}
isOrderingDirty$jscomp$inline_260 && recomputePluginOrdering();
isOrderingDirty$jscomp$inline_261 && recomputePluginOrdering();
var emptyObject$1 = {},
removedKeys = null,
removedKeyCount = 0,
@@ -10259,10 +10259,10 @@ batchedUpdatesImpl = function (fn, a) {
}
};
var roots = new Map(),
devToolsConfig$jscomp$inline_1126 = {
devToolsConfig$jscomp$inline_1130 = {
findFiberByHostInstance: getInstanceFromNode,
bundleType: 0,
version: "18.3.0-next-4a1cc2ddd-20230403",
version: "18.3.0-next-0700dd50b-20230404",
rendererPackageName: "react-native-renderer",
rendererConfig: {
getInspectorDataForViewTag: function () {
@@ -10291,10 +10291,10 @@ var roots = new Map(),
} catch (err) {}
return hook.checkDCE ? !0 : !1;
})({
bundleType: devToolsConfig$jscomp$inline_1126.bundleType,
version: devToolsConfig$jscomp$inline_1126.version,
rendererPackageName: devToolsConfig$jscomp$inline_1126.rendererPackageName,
rendererConfig: devToolsConfig$jscomp$inline_1126.rendererConfig,
bundleType: devToolsConfig$jscomp$inline_1130.bundleType,
version: devToolsConfig$jscomp$inline_1130.version,
rendererPackageName: devToolsConfig$jscomp$inline_1130.rendererPackageName,
rendererConfig: devToolsConfig$jscomp$inline_1130.rendererConfig,
overrideHookState: null,
overrideHookStateDeletePath: null,
overrideHookStateRenamePath: null,
@@ -10310,14 +10310,14 @@ var roots = new Map(),
return null === fiber ? null : fiber.stateNode;
},
findFiberByHostInstance:
devToolsConfig$jscomp$inline_1126.findFiberByHostInstance ||
devToolsConfig$jscomp$inline_1130.findFiberByHostInstance ||
emptyFindFiberByHostInstance,
findHostInstancesForRefresh: null,
scheduleRefresh: null,
scheduleRoot: null,
setRefreshHandler: null,
getCurrentFiber: null,
reconcilerVersion: "18.3.0-next-4a1cc2ddd-20230403"
reconcilerVersion: "18.3.0-next-0700dd50b-20230404"
});
exports.createPortal = function (children, containerTag) {
return createPortal$1(
@@ -10395,6 +10395,15 @@ exports.getNodeFromInternalInstanceHandle = function (internalInstanceHandle) {
exports.getPublicInstanceFromInternalInstanceHandle = function (
internalInstanceHandle
) {
if (6 === internalInstanceHandle.tag) {
var textInstance = internalInstanceHandle.stateNode;
null == textInstance.publicInstance &&
(textInstance.publicInstance =
ReactNativePrivateInterface.createPublicTextInstance(
internalInstanceHandle
));
return textInstance.publicInstance;
}
return getPublicInstance(internalInstanceHandle.stateNode);
};
exports.render = function (element, containerTag, callback, concurrentRoot) {
@@ -27698,7 +27698,7 @@ function createFiberRoot(
return root;
}
var ReactVersion = "18.3.0-next-4a1cc2ddd-20230403";
var ReactVersion = "18.3.0-next-0700dd50b-20230404";
function createPortal$1(
children,
@@ -9810,7 +9810,7 @@ var roots = new Map(),
devToolsConfig$jscomp$inline_1107 = {
findFiberByHostInstance: getInstanceFromTag,
bundleType: 0,
version: "18.3.0-next-4a1cc2ddd-20230403",
version: "18.3.0-next-0700dd50b-20230404",
rendererPackageName: "react-native-renderer",
rendererConfig: {
getInspectorDataForViewTag: function () {
@@ -9852,7 +9852,7 @@ var internals$jscomp$inline_1359 = {
scheduleRoot: null,
setRefreshHandler: null,
getCurrentFiber: null,
reconcilerVersion: "18.3.0-next-4a1cc2ddd-20230403"
reconcilerVersion: "18.3.0-next-0700dd50b-20230404"
};
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
var hook$jscomp$inline_1360 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
@@ -10518,7 +10518,7 @@ var roots = new Map(),
devToolsConfig$jscomp$inline_1185 = {
findFiberByHostInstance: getInstanceFromTag,
bundleType: 0,
version: "18.3.0-next-4a1cc2ddd-20230403",
version: "18.3.0-next-0700dd50b-20230404",
rendererPackageName: "react-native-renderer",
rendererConfig: {
getInspectorDataForViewTag: function () {
@@ -10573,7 +10573,7 @@ var roots = new Map(),
scheduleRoot: null,
setRefreshHandler: null,
getCurrentFiber: null,
reconcilerVersion: "18.3.0-next-4a1cc2ddd-20230403"
reconcilerVersion: "18.3.0-next-0700dd50b-20230404"
});
exports.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = {
computeComponentStackForErrorReporting: function (reactTag) {
@@ -215,6 +215,7 @@ export type ReactNativeType = {
export opaque type Node = mixed;
export opaque type InternalInstanceHandle = mixed;
type PublicInstance = mixed;
type PublicTextInstance = mixed;
export type ReactFabricType = {
findHostInstance_DEPRECATED<TElementType: ElementType>(
@@ -244,7 +245,7 @@ export type ReactFabricType = {
): ?Node,
getPublicInstanceFromInternalInstanceHandle(
internalInstanceHandle: InternalInstanceHandle,
): PublicInstance,
): PublicInstance | PublicTextInstance,
...
};