Stabilize reactFragments host node handle (#35642)

https://github.com/facebook/react/pull/34935 Introduced
`unstable_reactFragments` handle on DOM nodes to enable caching of
Observers.

This has been tested in production and is stable so it can be rolled out
with the Fragment Refs feature.
This commit is contained in:
Jack Pope
2026-03-03 15:44:11 -05:00
committed by GitHub
parent b7a43acc72
commit 1f477904db
3 changed files with 21 additions and 29 deletions
@@ -218,7 +218,7 @@ export type Instance = Element;
export type TextInstance = Text;
type InstanceWithFragmentHandles = Instance & {
unstable_reactFragments?: Set<FragmentInstanceType>,
reactFragments?: Set<FragmentInstanceType>,
};
declare class ActivityInterface extends Comment {}
@@ -3578,10 +3578,10 @@ function addFragmentHandleToInstance(
fragmentInstance: FragmentInstanceType,
): void {
if (enableFragmentRefsInstanceHandles) {
if (instance.unstable_reactFragments == null) {
instance.unstable_reactFragments = new Set();
if (instance.reactFragments == null) {
instance.reactFragments = new Set();
}
instance.unstable_reactFragments.add(fragmentInstance);
instance.reactFragments.add(fragmentInstance);
}
}
@@ -3647,8 +3647,8 @@ export function deleteChildFromFragmentInstance(
}
}
if (enableFragmentRefsInstanceHandles) {
if (instance.unstable_reactFragments != null) {
instance.unstable_reactFragments.delete(fragmentInstance);
if (instance.reactFragments != null) {
instance.reactFragments.delete(fragmentInstance);
}
}
}
@@ -137,26 +137,18 @@ describe('FragmentRefs', () => {
const childB = document.querySelector('#childB');
const childC = document.querySelector('#childC');
expect(childA.unstable_reactFragments.has(fragmentRef.current)).toBe(true);
expect(childB.unstable_reactFragments.has(fragmentRef.current)).toBe(true);
expect(childC.unstable_reactFragments.has(fragmentRef.current)).toBe(false);
expect(childA.unstable_reactFragments.has(fragmentParentRef.current)).toBe(
true,
);
expect(childB.unstable_reactFragments.has(fragmentParentRef.current)).toBe(
true,
);
expect(childC.unstable_reactFragments.has(fragmentParentRef.current)).toBe(
true,
);
expect(childA.reactFragments.has(fragmentRef.current)).toBe(true);
expect(childB.reactFragments.has(fragmentRef.current)).toBe(true);
expect(childC.reactFragments.has(fragmentRef.current)).toBe(false);
expect(childA.reactFragments.has(fragmentParentRef.current)).toBe(true);
expect(childB.reactFragments.has(fragmentParentRef.current)).toBe(true);
expect(childC.reactFragments.has(fragmentParentRef.current)).toBe(true);
await act(() => root.render(<Test show={true} />));
const childD = document.querySelector('#childD');
expect(childD.unstable_reactFragments.has(fragmentRef.current)).toBe(false);
expect(childD.unstable_reactFragments.has(fragmentParentRef.current)).toBe(
true,
);
expect(childD.reactFragments.has(fragmentRef.current)).toBe(false);
expect(childD.reactFragments.has(fragmentParentRef.current)).toBe(true);
});
describe('focus methods', () => {
@@ -1104,7 +1096,7 @@ describe('FragmentRefs', () => {
}
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
const fragmentInstances = entry.target.unstable_reactFragments;
const fragmentInstances = entry.target.reactFragments;
if (fragmentInstances) {
Array.from(fragmentInstances).forEach(fInstance => {
const cbs = targetToCallbackMap.get(fInstance) || [];
@@ -124,7 +124,7 @@ export type TextInstance = {
export type HydratableInstance = Instance | TextInstance;
export type PublicInstance = ReactNativePublicInstance;
type PublicInstanceWithFragmentHandles = PublicInstance & {
unstable_reactFragments?: Set<FragmentInstanceType>,
reactFragments?: Set<FragmentInstanceType>,
};
export type Container = {
containerTag: number,
@@ -856,10 +856,10 @@ function addFragmentHandleToInstance(
fragmentInstance: FragmentInstanceType,
): void {
if (enableFragmentRefsInstanceHandles) {
if (instance.unstable_reactFragments == null) {
instance.unstable_reactFragments = new Set();
if (instance.reactFragments == null) {
instance.reactFragments = new Set();
}
instance.unstable_reactFragments.add(fragmentInstance);
instance.reactFragments.add(fragmentInstance);
}
}
@@ -924,8 +924,8 @@ export function deleteChildFromFragmentInstance(
instance,
): any): PublicInstanceWithFragmentHandles);
if (enableFragmentRefsInstanceHandles) {
if (publicInstance.unstable_reactFragments != null) {
publicInstance.unstable_reactFragments.delete(fragmentInstance);
if (publicInstance.reactFragments != null) {
publicInstance.reactFragments.delete(fragmentInstance);
}
}
}