import type {
Instance,
TextInstance,
ActivityInstance,
SuspenseInstance,
Container,
ChildSet,
FragmentInstanceType,
} from './ReactFiberConfig';
import type {Fiber, FiberRoot} from './ReactInternalTypes';
import {
HostRoot,
HostComponent,
HostHoistable,
HostSingleton,
HostText,
HostPortal,
DehydratedFragment,
Fragment,
} from './ReactWorkTags';
import {ContentReset, Placement} from './ReactFiberFlags';
import {
supportsMutation,
supportsResources,
supportsSingletons,
commitMount,
commitUpdate,
resetTextContent,
commitTextUpdate,
appendChild,
appendChildToContainer,
insertBefore,
insertInContainerBefore,
replaceContainerChildren,
hideDehydratedBoundary,
hideInstance,
hideTextInstance,
unhideDehydratedBoundary,
unhideInstance,
unhideTextInstance,
commitHydratedInstance,
commitHydratedContainer,
commitHydratedActivityInstance,
commitHydratedSuspenseInstance,
removeChildFromContainer,
removeChild,
acquireSingletonInstance,
releaseSingletonInstance,
isSingletonScope,
commitNewChildToFragmentInstance,
deleteChildFromFragmentInstance,
} from './ReactFiberConfig';
import {captureCommitPhaseError} from './ReactFiberWorkLoop';
import {trackHostMutation} from './ReactFiberMutationTracking';
import {runWithFiberInDEV} from './ReactCurrentFiber';
import {enableFragmentRefs} from 'shared/ReactFeatureFlags';
export function commitHostMount(finishedWork: Fiber) {
const type = finishedWork.type;
const props = finishedWork.memoizedProps;
const instance: Instance = finishedWork.stateNode;
try {
if (__DEV__) {
runWithFiberInDEV(
finishedWork,
commitMount,
instance,
type,
props,
finishedWork,
);
} else {
commitMount(instance, type, props, finishedWork);
}
} catch (error) {
captureCommitPhaseError(finishedWork, finishedWork.return, error);
}
}
export function commitHostHydratedInstance(finishedWork: Fiber) {
const type = finishedWork.type;
const props = finishedWork.memoizedProps;
const instance: Instance = finishedWork.stateNode;
try {
if (__DEV__) {
runWithFiberInDEV(
finishedWork,
commitHydratedInstance,
instance,
type,
props,
finishedWork,
);
} else {
commitHydratedInstance(instance, type, props, finishedWork);
}
} catch (error) {
captureCommitPhaseError(finishedWork, finishedWork.return, error);
}
}
export function commitHostUpdate(
finishedWork: Fiber,
newProps: any,
oldProps: any,
): void {
try {
if (__DEV__) {
runWithFiberInDEV(
finishedWork,
commitUpdate,
finishedWork.stateNode,
finishedWork.type,
oldProps,
newProps,
finishedWork,
);
} else {
commitUpdate(
finishedWork.stateNode,
finishedWork.type,
oldProps,
newProps,
finishedWork,
);
}
} catch (error) {
captureCommitPhaseError(finishedWork, finishedWork.return, error);
}
}
export function commitHostTextUpdate(
finishedWork: Fiber,
newText: string,
oldText: string,
) {
const textInstance: TextInstance = finishedWork.stateNode;
try {
if (__DEV__) {
runWithFiberInDEV(
finishedWork,
commitTextUpdate,
textInstance,
oldText,
newText,
);
} else {
commitTextUpdate(textInstance, oldText, newText);
}
trackHostMutation();
} catch (error) {
captureCommitPhaseError(finishedWork, finishedWork.return, error);
}
}
export function commitHostResetTextContent(finishedWork: Fiber) {
const instance: Instance = finishedWork.stateNode;
try {
if (__DEV__) {
runWithFiberInDEV(finishedWork, resetTextContent, instance);
} else {
resetTextContent(instance);
}
trackHostMutation();
} catch (error) {
captureCommitPhaseError(finishedWork, finishedWork.return, error);
}
}
export function commitShowHideSuspenseBoundary(node: Fiber, isHidden: boolean) {
try {
const instance = node.stateNode;
if (isHidden) {
if (__DEV__) {
runWithFiberInDEV(node, hideDehydratedBoundary, instance);
} else {
hideDehydratedBoundary(instance);
}
} else {
if (__DEV__) {
runWithFiberInDEV(node, unhideDehydratedBoundary, node.stateNode);
} else {
unhideDehydratedBoundary(node.stateNode);
}
}
} catch (error) {
captureCommitPhaseError(node, node.return, error);
}
}
export function commitShowHideHostInstance(node: Fiber, isHidden: boolean) {
try {
const instance = node.stateNode;
if (isHidden) {
if (__DEV__) {
runWithFiberInDEV(node, hideInstance, instance);
} else {
hideInstance(instance);
}
} else {
if (__DEV__) {
runWithFiberInDEV(
node,
unhideInstance,
node.stateNode,
node.memoizedProps,
);
} else {
unhideInstance(node.stateNode, node.memoizedProps);
}
}
} catch (error) {
captureCommitPhaseError(node, node.return, error);
}
}
export function commitShowHideHostTextInstance(node: Fiber, isHidden: boolean) {
try {
const instance = node.stateNode;
if (isHidden) {
if (__DEV__) {
runWithFiberInDEV(node, hideTextInstance, instance);
} else {
hideTextInstance(instance);
}
} else {
if (__DEV__) {
runWithFiberInDEV(
node,
unhideTextInstance,
instance,
node.memoizedProps,
);
} else {
unhideTextInstance(instance, node.memoizedProps);
}
}
trackHostMutation();
} catch (error) {
captureCommitPhaseError(node, node.return, error);
}
}
export function commitNewChildToFragmentInstances(
fiber: Fiber,
parentFragmentInstances: null | Array<FragmentInstanceType>,
): void {
if (
fiber.tag !== HostComponent ||
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 (isHostParent(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 (isHostParent(parent)) {
return;
}
parent = parent.return;
}
}
function isHostParent(fiber: Fiber): boolean {
return (
fiber.tag === HostComponent ||
fiber.tag === HostRoot ||
(supportsResources ? fiber.tag === HostHoistable : false) ||
(supportsSingletons
? fiber.tag === HostSingleton && isSingletonScope(fiber.type)
: false) ||
fiber.tag === HostPortal
);
}
function isFragmentInstanceParent(fiber: Fiber): boolean {
return fiber && fiber.tag === Fragment && fiber.stateNode !== null;
}
function getHostSibling(fiber: Fiber): ?Instance {
let node: Fiber = fiber;
siblings: while (true) {
while (node.sibling === null) {
if (node.return === null || isHostParent(node.return)) {
return null;
}
node = node.return;
}
node.sibling.return = node.return;
node = node.sibling;
while (
node.tag !== HostComponent &&
node.tag !== HostText &&
node.tag !== DehydratedFragment
) {
if (
supportsSingletons &&
node.tag === HostSingleton &&
isSingletonScope(node.type)
) {
continue siblings;
}
if (node.flags & Placement) {
continue siblings;
}
if (node.child === null || node.tag === HostPortal) {
continue siblings;
} else {
node.child.return = node;
node = node.child;
}
}
if (!(node.flags & Placement)) {
return node.stateNode;
}
}
}
function insertOrAppendPlacementNodeIntoContainer(
node: Fiber,
before: ?Instance,
parent: Container,
parentFragmentInstances: null | Array<FragmentInstanceType>,
): void {
const {tag} = node;
const isHost = tag === HostComponent || tag === HostText;
if (isHost) {
const stateNode = node.stateNode;
if (before) {
insertInContainerBefore(parent, stateNode, before);
} else {
appendChildToContainer(parent, stateNode);
}
if (enableFragmentRefs) {
commitNewChildToFragmentInstances(node, parentFragmentInstances);
}
trackHostMutation();
return;
} else if (tag === HostPortal) {
return;
}
if (
(supportsSingletons ? tag === HostSingleton : false) &&
isSingletonScope(node.type)
) {
parent = node.stateNode;
before = null;
}
const child = node.child;
if (child !== null) {
insertOrAppendPlacementNodeIntoContainer(
child,
before,
parent,
parentFragmentInstances,
);
let sibling = child.sibling;
while (sibling !== null) {
insertOrAppendPlacementNodeIntoContainer(
sibling,
before,
parent,
parentFragmentInstances,
);
sibling = sibling.sibling;
}
}
}
function insertOrAppendPlacementNode(
node: Fiber,
before: ?Instance,
parent: Instance,
parentFragmentInstances: null | Array<FragmentInstanceType>,
): void {
const {tag} = node;
const isHost = tag === HostComponent || tag === HostText;
if (isHost) {
const stateNode = node.stateNode;
if (before) {
insertBefore(parent, stateNode, before);
} else {
appendChild(parent, stateNode);
}
if (enableFragmentRefs) {
commitNewChildToFragmentInstances(node, parentFragmentInstances);
}
trackHostMutation();
return;
} else if (tag === HostPortal) {
return;
}
if (
(supportsSingletons ? tag === HostSingleton : false) &&
isSingletonScope(node.type)
) {
parent = node.stateNode;
}
const child = node.child;
if (child !== null) {
insertOrAppendPlacementNode(child, before, parent, parentFragmentInstances);
let sibling = child.sibling;
while (sibling !== null) {
insertOrAppendPlacementNode(
sibling,
before,
parent,
parentFragmentInstances,
);
sibling = sibling.sibling;
}
}
}
function commitPlacement(finishedWork: Fiber): void {
let hostParentFiber;
let parentFragmentInstances = null;
let parentFiber = finishedWork.return;
while (parentFiber !== null) {
if (enableFragmentRefs && isFragmentInstanceParent(parentFiber)) {
const fragmentInstance: FragmentInstanceType = parentFiber.stateNode;
if (parentFragmentInstances === null) {
parentFragmentInstances = [fragmentInstance];
} else {
parentFragmentInstances.push(fragmentInstance);
}
}
if (isHostParent(parentFiber)) {
hostParentFiber = parentFiber;
break;
}
parentFiber = parentFiber.return;
}
if (!supportsMutation) {
if (enableFragmentRefs) {
commitImmutablePlacementNodeToFragmentInstances(
finishedWork,
parentFragmentInstances,
);
}
return;
}
if (hostParentFiber == null) {
throw new Error(
'Expected to find a host parent. This error is likely caused by a bug ' +
'in React. Please file an issue.',
);
}
switch (hostParentFiber.tag) {
case HostSingleton: {
if (supportsSingletons) {
const parent: Instance = hostParentFiber.stateNode;
const before = getHostSibling(finishedWork);
insertOrAppendPlacementNode(
finishedWork,
before,
parent,
parentFragmentInstances,
);
break;
}
}
case HostComponent: {
const parent: Instance = hostParentFiber.stateNode;
if (hostParentFiber.flags & ContentReset) {
resetTextContent(parent);
hostParentFiber.flags &= ~ContentReset;
}
const before = getHostSibling(finishedWork);
insertOrAppendPlacementNode(
finishedWork,
before,
parent,
parentFragmentInstances,
);
break;
}
case HostRoot:
case HostPortal: {
const parent: Container = hostParentFiber.stateNode.containerInfo;
const before = getHostSibling(finishedWork);
insertOrAppendPlacementNodeIntoContainer(
finishedWork,
before,
parent,
parentFragmentInstances,
);
break;
}
default:
throw new Error(
'Invalid host parent fiber. This error is likely caused by a bug ' +
'in React. Please file an issue.',
);
}
}
function commitImmutablePlacementNodeToFragmentInstances(
finishedWork: Fiber,
parentFragmentInstances: null | Array<FragmentInstanceType>,
): void {
if (!enableFragmentRefs) {
return;
}
const isHost = finishedWork.tag === HostComponent;
if (isHost) {
commitNewChildToFragmentInstances(finishedWork, parentFragmentInstances);
return;
} else if (finishedWork.tag === HostPortal) {
return;
}
const child = finishedWork.child;
if (child !== null) {
commitImmutablePlacementNodeToFragmentInstances(
child,
parentFragmentInstances,
);
let sibling = child.sibling;
while (sibling !== null) {
commitImmutablePlacementNodeToFragmentInstances(
sibling,
parentFragmentInstances,
);
sibling = sibling.sibling;
}
}
}
export function commitHostPlacement(finishedWork: Fiber) {
try {
if (__DEV__) {
runWithFiberInDEV(finishedWork, commitPlacement, finishedWork);
} else {
commitPlacement(finishedWork);
}
} catch (error) {
captureCommitPhaseError(finishedWork, finishedWork.return, error);
}
}
export function commitHostRemoveChildFromContainer(
deletedFiber: Fiber,
nearestMountedAncestor: Fiber,
parentContainer: Container,
hostInstance: Instance | TextInstance,
) {
try {
if (__DEV__) {
runWithFiberInDEV(
deletedFiber,
removeChildFromContainer,
parentContainer,
hostInstance,
);
} else {
removeChildFromContainer(parentContainer, hostInstance);
}
trackHostMutation();
} catch (error) {
captureCommitPhaseError(deletedFiber, nearestMountedAncestor, error);
}
}
export function commitHostRemoveChild(
deletedFiber: Fiber,
nearestMountedAncestor: Fiber,
parentInstance: Instance,
hostInstance: Instance | TextInstance,
) {
try {
if (__DEV__) {
runWithFiberInDEV(
deletedFiber,
removeChild,
parentInstance,
hostInstance,
);
} else {
removeChild(parentInstance, hostInstance);
}
trackHostMutation();
} catch (error) {
captureCommitPhaseError(deletedFiber, nearestMountedAncestor, error);
}
}
export function commitHostRootContainerChildren(
root: FiberRoot,
finishedWork: Fiber,
) {
const containerInfo = root.containerInfo;
const pendingChildren = root.pendingChildren;
try {
if (__DEV__) {
runWithFiberInDEV(
finishedWork,
replaceContainerChildren,
containerInfo,
pendingChildren,
);
} else {
replaceContainerChildren(containerInfo, pendingChildren);
}
trackHostMutation();
} catch (error) {
captureCommitPhaseError(finishedWork, finishedWork.return, error);
}
}
export function commitHostPortalContainerChildren(
portal: {
containerInfo: Container,
pendingChildren: ChildSet,
...
},
finishedWork: Fiber,
pendingChildren: ChildSet,
) {
const containerInfo = portal.containerInfo;
try {
if (__DEV__) {
runWithFiberInDEV(
finishedWork,
replaceContainerChildren,
containerInfo,
pendingChildren,
);
} else {
replaceContainerChildren(containerInfo, pendingChildren);
}
} catch (error) {
captureCommitPhaseError(finishedWork, finishedWork.return, error);
}
}
export function commitHostHydratedContainer(
root: FiberRoot,
finishedWork: Fiber,
) {
try {
if (__DEV__) {
runWithFiberInDEV(
finishedWork,
commitHydratedContainer,
root.containerInfo,
);
} else {
commitHydratedContainer(root.containerInfo);
}
} catch (error) {
captureCommitPhaseError(finishedWork, finishedWork.return, error);
}
}
export function commitHostHydratedActivity(
activityInstance: ActivityInstance,
finishedWork: Fiber,
) {
try {
if (__DEV__) {
runWithFiberInDEV(
finishedWork,
commitHydratedActivityInstance,
activityInstance,
);
} else {
commitHydratedActivityInstance(activityInstance);
}
} catch (error) {
captureCommitPhaseError(finishedWork, finishedWork.return, error);
}
}
export function commitHostHydratedSuspense(
suspenseInstance: SuspenseInstance,
finishedWork: Fiber,
) {
try {
if (__DEV__) {
runWithFiberInDEV(
finishedWork,
commitHydratedSuspenseInstance,
suspenseInstance,
);
} else {
commitHydratedSuspenseInstance(suspenseInstance);
}
} catch (error) {
captureCommitPhaseError(finishedWork, finishedWork.return, error);
}
}
export function commitHostSingletonAcquisition(finishedWork: Fiber) {
const singleton = finishedWork.stateNode;
const props = finishedWork.memoizedProps;
try {
if (__DEV__) {
runWithFiberInDEV(
finishedWork,
acquireSingletonInstance,
finishedWork.type,
props,
singleton,
finishedWork,
);
} else {
acquireSingletonInstance(
finishedWork.type,
props,
singleton,
finishedWork,
);
}
} catch (error) {
captureCommitPhaseError(finishedWork, finishedWork.return, error);
}
}
export function commitHostSingletonRelease(releasingWork: Fiber) {
if (__DEV__) {
runWithFiberInDEV(
releasingWork,
releaseSingletonInstance,
releasingWork.stateNode,
);
} else {
releaseSingletonInstance(releasingWork.stateNode);
}
}