main
js 117 lines 3.38 KB
Raw
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 }