@samitouri / QOS-React-2 / commits / 22e4f993c7

[Fiber] Extract Fragment instance commit helpers into their own module (#37167)

Just a small refactor to consolidate FragmentInstance helpers into one module

Jack Pope committed Aug 11, 2026 at 18:46 UTC 22e4f993c7ce9373c95aef093b003f84249e2045
3 files changed +130 -101
packages/react-reconciler/src/ReactFiberCommitHostEffects.js
+10 -100
@@ -26,7 +26,6 @@ import {
26 HostText,
27 HostPortal,
28 DehydratedFragment,
29 - Fragment,
29 } from './ReactWorkTags';
30 import {ContentReset, Placement} from './ReactFiberFlags';
31 import {
@@ -57,17 +56,16 @@ import {
56 acquireSingletonInstance,
57 releaseSingletonInstance,
58 isSingletonScope,
60 - commitNewChildToFragmentInstance,
61 - deleteChildFromFragmentInstance,
59 } from './ReactFiberConfig';
60 import {captureCommitPhaseError} from './ReactFiberWorkLoop';
61 import {trackHostMutation} from './ReactFiberMutationTracking';
62
63 import {runWithFiberInDEV} from './ReactCurrentFiber';
64 +import {enableFragmentRefs} from 'shared/ReactFeatureFlags';
65 import {
68 - enableFragmentRefs,
69 - enableFragmentRefsTextNodes,
70 -} from 'shared/ReactFeatureFlags';
66 + commitNewChildToFragmentInstances,
67 + getParentFragmentInstances,
68 +} from './ReactFiberFragmentInstance';
69
70 export function commitHostMount(finishedWork: Fiber) {
71 const type = finishedWork.type;
@@ -256,58 +254,6 @@ export function commitShowHideHostTextInstance(node: Fiber, isHidden: boolean) {
254 }
255 }
256
259 -export function commitNewChildToFragmentInstances(
260 - fiber: Fiber,
261 - parentFragmentInstances: null | Array<FragmentInstanceType>,
262 -): void {
263 - if (
264 - (fiber.tag !== HostComponent &&
265 - fiber.tag !== HostSingleton &&
266 - !(enableFragmentRefsTextNodes && fiber.tag === HostText)) ||
267 - // Only run fragment insertion effects for initial insertions
268 - fiber.alternate !== null ||
269 - parentFragmentInstances === null
270 - ) {
271 - return;
272 - }
273 - for (let i = 0; i < parentFragmentInstances.length; i++) {
274 - const fragmentInstance = parentFragmentInstances[i];
275 - commitNewChildToFragmentInstance(fiber.stateNode, fragmentInstance);
276 - }
277 -}
278 -
279 -export function commitFragmentInstanceInsertionEffects(fiber: Fiber): void {
280 - let parent = fiber.return;
281 - while (parent !== null) {
282 - if (isFragmentInstanceParent(parent)) {
283 - const fragmentInstance: FragmentInstanceType = parent.stateNode;
284 - commitNewChildToFragmentInstance(fiber.stateNode, fragmentInstance);
285 - }
286 -
287 - if (isFragmentInstanceHostBoundary(parent)) {
288 - return;
289 - }
290 -
291 - parent = parent.return;
292 - }
293 -}
294 -
295 -export function commitFragmentInstanceDeletionEffects(fiber: Fiber): void {
296 - let parent = fiber.return;
297 - while (parent !== null) {
298 - if (isFragmentInstanceParent(parent)) {
299 - const fragmentInstance: FragmentInstanceType = parent.stateNode;
300 - deleteChildFromFragmentInstance(fiber.stateNode, fragmentInstance);
301 - }
302 -
303 - if (isFragmentInstanceHostBoundary(parent)) {
304 - return;
305 - }
306 -
307 - parent = parent.return;
308 - }
309 -}
310 -
257 function isHostParent(fiber: Fiber): boolean {
258 return (
259 fiber.tag === HostComponent ||
@@ -322,24 +268,6 @@ function isHostParent(fiber: Fiber): boolean {
268 );
269 }
270
325 -// HostPortal / HostHoistable are host parents for placement, but not for
326 -// fragment instance ancestry — commit bookkeeping walks past them so it
327 -// matches getFragmentParentInstanceOrContainerFiber. HostSingleton is a
328 -// fragment host boundary (and a collected child) even when it is not a
329 -// placement scope.
330 -function isFragmentInstanceHostBoundary(fiber: Fiber): boolean {
331 - return (
332 - fiber.tag === HostComponent ||
333 - fiber.tag === HostRoot ||
334 - // $FlowFixMe[constant-condition]
335 - (supportsSingletons ? fiber.tag === HostSingleton : false)
336 - );
337 -}
338 -
339 -function isFragmentInstanceParent(fiber: Fiber): boolean {
340 - return fiber && fiber.tag === Fragment && fiber.stateNode !== null;
341 -}
342 -
271 function getHostSibling(fiber: Fiber): ?Instance {
272 // We're going to search forward into the tree until we find a sibling host
273 // node. Unfortunately, if multiple insertions are done in a row we have to
@@ -524,37 +452,19 @@ function insertOrAppendPlacementNode(
452 function commitPlacement(finishedWork: Fiber): void {
453 // Recursively insert all host nodes into the parent.
454 let hostParentFiber;
527 - let parentFragmentInstances = null;
528 - let collectFragmentInstances = enableFragmentRefs;
455 let parentFiber = finishedWork.return;
456 while (parentFiber !== null) {
531 - if (collectFragmentInstances && isFragmentInstanceParent(parentFiber)) {
532 - const fragmentInstance: FragmentInstanceType = parentFiber.stateNode;
533 - if (parentFragmentInstances === null) {
534 - parentFragmentInstances = [fragmentInstance];
535 - } else {
536 - parentFragmentInstances.push(fragmentInstance);
537 - }
538 - }
539 - if (hostParentFiber === undefined && isHostParent(parentFiber)) {
540 - // Nearest host parent for placement. Portals still win here so
541 - // children insert into the portal container.
457 + if (isHostParent(parentFiber)) {
458 hostParentFiber = parentFiber;
543 - }
544 - if (
545 - collectFragmentInstances &&
546 - isFragmentInstanceHostBoundary(parentFiber)
547 - ) {
548 - // Stop collecting at HostComponent / HostRoot / HostSingleton.
549 - // Placement can continue past non-scope singletons to HostRoot, and
550 - // past portals (already recorded above) to fragment ancestors.
551 - collectFragmentInstances = false;
552 - }
553 - if (hostParentFiber !== undefined && !collectFragmentInstances) {
459 break;
460 }
461 parentFiber = parentFiber.return;
462 }
463 + // Fragment ancestry is collected separately so portals remain placement
464 + // parents while fragment bookkeeping still walks past them to ancestors.
465 + const parentFragmentInstances = enableFragmentRefs
466 + ? getParentFragmentInstances(finishedWork)
467 + : null;
468
469 // $FlowFixMe[constant-condition]
470 if (!supportsMutation) {
packages/react-reconciler/src/ReactFiberCommitWork.js
+3 -1
@@ -255,9 +255,11 @@ import {
255 commitHostRemoveChild,
256 commitHostSingletonAcquisition,
257 commitHostSingletonRelease,
258 +} from './ReactFiberCommitHostEffects';
259 +import {
260 commitFragmentInstanceDeletionEffects,
261 commitFragmentInstanceInsertionEffects,
260 -} from './ReactFiberCommitHostEffects';
262 +} from './ReactFiberFragmentInstance';
263 import {
264 trackEnterViewTransitions,
265 commitEnterViewTransitions,
packages/react-reconciler/src/ReactFiberFragmentInstance.js new
+117
@@ -0,0 +1,117 @@
1 +/**
2 + * Copyright (c) Meta Platforms, Inc. and affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +import type {FragmentInstanceType} from './ReactFiberConfig';
11 +import type {Fiber} from './ReactInternalTypes';
12 +
13 +import {
14 + HostRoot,
15 + HostComponent,
16 + HostSingleton,
17 + HostText,
18 + Fragment,
19 +} from './ReactWorkTags';
20 +import {
21 + supportsSingletons,
22 + commitNewChildToFragmentInstance,
23 + deleteChildFromFragmentInstance,
24 +} from './ReactFiberConfig';
25 +import {enableFragmentRefsTextNodes} from 'shared/ReactFeatureFlags';
26 +
27 +export function commitNewChildToFragmentInstances(
28 + fiber: Fiber,
29 + parentFragmentInstances: null | Array<FragmentInstanceType>,
30 +): void {
31 + if (
32 + (fiber.tag !== HostComponent &&
33 + fiber.tag !== HostSingleton &&
34 + !(enableFragmentRefsTextNodes && fiber.tag === HostText)) ||
35 + // Only run fragment insertion effects for initial insertions
36 + fiber.alternate !== null ||
37 + parentFragmentInstances === null
38 + ) {
39 + return;
40 + }
41 + for (let i = 0; i < parentFragmentInstances.length; i++) {
42 + const fragmentInstance = parentFragmentInstances[i];
43 + commitNewChildToFragmentInstance(fiber.stateNode, fragmentInstance);
44 + }
45 +}
46 +
47 +export function commitFragmentInstanceInsertionEffects(fiber: Fiber): void {
48 + let parent = fiber.return;
49 + while (parent !== null) {
50 + if (isFragmentInstanceParent(parent)) {
51 + const fragmentInstance: FragmentInstanceType = parent.stateNode;
52 + commitNewChildToFragmentInstance(fiber.stateNode, fragmentInstance);
53 + }
54 +
55 + if (isFragmentInstanceHostBoundary(parent)) {
56 + return;
57 + }
58 +
59 + parent = parent.return;
60 + }
61 +}
62 +
63 +export function commitFragmentInstanceDeletionEffects(fiber: Fiber): void {
64 + let parent = fiber.return;
65 + while (parent !== null) {
66 + if (isFragmentInstanceParent(parent)) {
67 + const fragmentInstance: FragmentInstanceType = parent.stateNode;
68 + deleteChildFromFragmentInstance(fiber.stateNode, fragmentInstance);
69 + }
70 +
71 + if (isFragmentInstanceHostBoundary(parent)) {
72 + return;
73 + }
74 +
75 + parent = parent.return;
76 + }
77 +}
78 +
79 +export function getParentFragmentInstances(
80 + fiber: Fiber,
81 +): null | Array<FragmentInstanceType> {
82 + let parentFragmentInstances = null;
83 + let parent = fiber.return;
84 + while (parent !== null) {
85 + if (isFragmentInstanceParent(parent)) {
86 + const fragmentInstance: FragmentInstanceType = parent.stateNode;
87 + if (parentFragmentInstances === null) {
88 + parentFragmentInstances = [fragmentInstance];
89 + } else {
90 + parentFragmentInstances.push(fragmentInstance);
91 + }
92 + }
93 + if (isFragmentInstanceHostBoundary(parent)) {
94 + break;
95 + }
96 + parent = parent.return;
97 + }
98 + return parentFragmentInstances;
99 +}
100 +
101 +// HostPortal / HostHoistable are host parents for placement, but not for
102 +// fragment instance ancestry — commit bookkeeping walks past them so it
103 +// matches getFragmentParentInstanceOrContainerFiber. HostSingleton is a
104 +// fragment host boundary (and a collected child) even when it is not a
105 +// placement scope.
106 +function isFragmentInstanceHostBoundary(fiber: Fiber): boolean {
107 + return (
108 + fiber.tag === HostComponent ||
109 + fiber.tag === HostRoot ||
110 + // $FlowFixMe[constant-condition]
111 + (supportsSingletons ? fiber.tag === HostSingleton : false)
112 + );
113 +}
114 +
115 +function isFragmentInstanceParent(fiber: Fiber): boolean {
116 + return fiber && fiber.tag === Fragment && fiber.stateNode !== null;
117 +}