import type {
Instance,
TextInstance,
SuspenseInstance,
Container,
ChildSet,
} from './ReactFiberConfig';
import type {Fiber, FiberRoot} from './ReactInternalTypes';
import {
HostRoot,
HostComponent,
HostHoistable,
HostSingleton,
HostText,
HostPortal,
DehydratedFragment,
} from './ReactWorkTags';
import {ContentReset, Placement} from './ReactFiberFlags';
import {
supportsMutation,
supportsResources,
supportsSingletons,
commitMount,
commitUpdate,
resetTextContent,
commitTextUpdate,
appendChild,
appendChildToContainer,
insertBefore,
insertInContainerBefore,
replaceContainerChildren,
hideInstance,
hideTextInstance,
unhideInstance,
unhideTextInstance,
commitHydratedContainer,
commitHydratedSuspenseInstance,
removeChildFromContainer,
removeChild,
clearSingleton,
acquireSingletonInstance,
} from './ReactFiberConfig';
import {captureCommitPhaseError} from './ReactFiberWorkLoop';
import {runWithFiberInDEV} from './ReactCurrentFiber';
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 commitHostUpdate(
finishedWork: Fiber,
newProps: any,
oldProps: any,
) {
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);
}
} 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);
}
} catch (error) {
captureCommitPhaseError(finishedWork, finishedWork.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);
}
}
} catch (error) {
captureCommitPhaseError(node, node.return, error);
}
}
function getHostParentFiber(fiber: Fiber): Fiber {
let parent = fiber.return;
while (parent !== null) {
if (isHostParent(parent)) {
return parent;
}
parent = parent.return;
}
throw new Error(
'Expected to find a host parent. This error is likely caused by a bug ' +
'in React. Please file an issue.',
);
}
function isHostParent(fiber: Fiber): boolean {
return (
fiber.tag === HostComponent ||
fiber.tag === HostRoot ||
(supportsResources ? fiber.tag === HostHoistable : false) ||
(supportsSingletons ? fiber.tag === HostSingleton : false) ||
fiber.tag === HostPortal
);
}
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 &&
(!supportsSingletons ? true : node.tag !== HostSingleton) &&
node.tag !== DehydratedFragment
) {
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,
): 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);
}
} else if (
tag === HostPortal ||
(supportsSingletons ? tag === HostSingleton : false)
) {
} else {
const child = node.child;
if (child !== null) {
insertOrAppendPlacementNodeIntoContainer(child, before, parent);
let sibling = child.sibling;
while (sibling !== null) {
insertOrAppendPlacementNodeIntoContainer(sibling, before, parent);
sibling = sibling.sibling;
}
}
}
}
function insertOrAppendPlacementNode(
node: Fiber,
before: ?Instance,
parent: Instance,
): 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);
}
} else if (
tag === HostPortal ||
(supportsSingletons ? tag === HostSingleton : false)
) {
} else {
const child = node.child;
if (child !== null) {
insertOrAppendPlacementNode(child, before, parent);
let sibling = child.sibling;
while (sibling !== null) {
insertOrAppendPlacementNode(sibling, before, parent);
sibling = sibling.sibling;
}
}
}
}
function commitPlacement(finishedWork: Fiber): void {
if (!supportsMutation) {
return;
}
if (supportsSingletons) {
if (finishedWork.tag === HostSingleton) {
return;
}
}
const parentFiber = getHostParentFiber(finishedWork);
switch (parentFiber.tag) {
case HostSingleton: {
if (supportsSingletons) {
const parent: Instance = parentFiber.stateNode;
const before = getHostSibling(finishedWork);
insertOrAppendPlacementNode(finishedWork, before, parent);
break;
}
}
case HostComponent: {
const parent: Instance = parentFiber.stateNode;
if (parentFiber.flags & ContentReset) {
resetTextContent(parent);
parentFiber.flags &= ~ContentReset;
}
const before = getHostSibling(finishedWork);
insertOrAppendPlacementNode(finishedWork, before, parent);
break;
}
case HostRoot:
case HostPortal: {
const parent: Container = parentFiber.stateNode.containerInfo;
const before = getHostSibling(finishedWork);
insertOrAppendPlacementNodeIntoContainer(finishedWork, before, parent);
break;
}
default:
throw new Error(
'Invalid host parent fiber. This error is likely caused by a bug ' +
'in React. Please file an issue.',
);
}
}
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);
}
} 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);
}
} 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);
}
} 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 commitHostHydratedSuspense(
suspenseInstance: SuspenseInstance,
finishedWork: Fiber,
) {
try {
if (__DEV__) {
runWithFiberInDEV(
finishedWork,
commitHydratedSuspenseInstance,
suspenseInstance,
);
} else {
commitHydratedSuspenseInstance(suspenseInstance);
}
} catch (error) {
captureCommitPhaseError(finishedWork, finishedWork.return, error);
}
}
export function commitHostSingleton(finishedWork: Fiber) {
const singleton = finishedWork.stateNode;
const props = finishedWork.memoizedProps;
try {
clearSingleton(singleton);
if (__DEV__) {
runWithFiberInDEV(
finishedWork,
acquireSingletonInstance,
finishedWork.type,
props,
singleton,
finishedWork,
);
} else {
acquireSingletonInstance(
finishedWork.type,
props,
singleton,
finishedWork,
);
}
} catch (error) {
captureCommitPhaseError(finishedWork, finishedWork.return, error);
}
}