/** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @flow */ import type {FragmentInstanceType} from './ReactFiberConfig'; import type {Fiber} from './ReactInternalTypes'; import { HostRoot, HostComponent, HostSingleton, HostText, Fragment, } from './ReactWorkTags'; import { supportsSingletons, commitNewChildToFragmentInstance, deleteChildFromFragmentInstance, } from './ReactFiberConfig'; import {enableFragmentRefsTextNodes} from 'shared/ReactFeatureFlags'; export function commitNewChildToFragmentInstances( fiber: Fiber, parentFragmentInstances: null | Array, ): void { if ( (fiber.tag !== HostComponent && fiber.tag !== HostSingleton && !(enableFragmentRefsTextNodes && fiber.tag === HostText)) || // Only run fragment insertion effects for initial insertions fiber.alternate !== null || parentFragmentInstances === null ) { return; } for (let i = 0; i < parentFragmentInstances.length; i++) { const fragmentInstance = parentFragmentInstances[i]; commitNewChildToFragmentInstance(fiber.stateNode, fragmentInstance); } } export function commitFragmentInstanceInsertionEffects(fiber: Fiber): void { let parent = fiber.return; while (parent !== null) { if (isFragmentInstanceParent(parent)) { const fragmentInstance: FragmentInstanceType = parent.stateNode; commitNewChildToFragmentInstance(fiber.stateNode, fragmentInstance); } if (isFragmentInstanceHostBoundary(parent)) { return; } parent = parent.return; } } export function commitFragmentInstanceDeletionEffects(fiber: Fiber): void { let parent = fiber.return; while (parent !== null) { if (isFragmentInstanceParent(parent)) { const fragmentInstance: FragmentInstanceType = parent.stateNode; deleteChildFromFragmentInstance(fiber.stateNode, fragmentInstance); } if (isFragmentInstanceHostBoundary(parent)) { return; } parent = parent.return; } } export function getParentFragmentInstances( fiber: Fiber, ): null | Array { let parentFragmentInstances = null; let parent = fiber.return; while (parent !== null) { if (isFragmentInstanceParent(parent)) { const fragmentInstance: FragmentInstanceType = parent.stateNode; if (parentFragmentInstances === null) { parentFragmentInstances = [fragmentInstance]; } else { parentFragmentInstances.push(fragmentInstance); } } if (isFragmentInstanceHostBoundary(parent)) { break; } parent = parent.return; } return parentFragmentInstances; } // HostPortal / HostHoistable are host parents for placement, but not for // fragment instance ancestry — commit bookkeeping walks past them so it // matches getFragmentParentInstanceOrContainerFiber. HostSingleton is a // fragment host boundary (and a collected child) even when it is not a // placement scope. function isFragmentInstanceHostBoundary(fiber: Fiber): boolean { return ( fiber.tag === HostComponent || fiber.tag === HostRoot || // $FlowFixMe[constant-condition] (supportsSingletons ? fiber.tag === HostSingleton : false) ); } function isFragmentInstanceParent(fiber: Fiber): boolean { return fiber && fiber.tag === Fragment && fiber.stateNode !== null; }