Skip to content

Commit

Permalink
Refactor commitPlacement to recursively insert nodes
Browse files Browse the repository at this point in the history
Fix Flow types
  • Loading branch information
trueadm committed Feb 7, 2020
1 parent 256d78d commit 513c18b
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 55 deletions.
8 changes: 7 additions & 1 deletion packages/react-dom/src/client/ReactDOM.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,14 @@ setBatchingImplementation(
batchedEventUpdates,
);

export type DOMInstance = Element & {_reactRootContainer: ?RootType, ...};
export type DOMHTMLInstance = HTMLElement & {
_reactRootContainer: ?RootType,
...
};

export type DOMContainer =
| (Element & {_reactRootContainer: ?RootType, ...})
| DOMInstance
| (Document & {_reactRootContainer: ?RootType, ...});

function createPortal(
Expand Down
36 changes: 18 additions & 18 deletions packages/react-dom/src/client/ReactDOMHostConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import {
} from '../shared/HTMLNodeType';
import dangerousStyleValue from '../shared/dangerousStyleValue';

import type {DOMContainer} from './ReactDOM';
import type {DOMContainer, DOMInstance, DOMHTMLInstance} from './ReactDOM';
import type {
ReactDOMEventResponder,
ReactDOMEventResponderInstance,
Expand Down Expand Up @@ -88,8 +88,8 @@ export type EventTargetChildElement = {
},
...
};
export type Container = Element | Document;
export type Instance = Element;
export type Container = DOMContainer;
export type Instance = DOMInstance;
export type TextInstance = Text;
export type SuspenseInstance = Comment & {_reactRetry?: () => void, ...};
export type HydratableInstance = Instance | TextInstance | SuspenseInstance;
Expand Down Expand Up @@ -252,15 +252,15 @@ export function createInstance(
} else {
parentNamespace = ((hostContext: any): HostContextProd);
}
const domElement: Instance = createElement(
const domElement = createElement(
type,
props,
rootContainerInstance,
parentNamespace,
);
precacheFiberNode(internalInstanceHandle, domElement);
updateFiberProps(domElement, props);
return domElement;
return ((domElement: any): DOMInstance);
}

export function appendInitialChild(
Expand Down Expand Up @@ -398,7 +398,7 @@ export function commitUpdate(
updateProperties(domElement, updatePayload, type, oldProps, newProps);
}

export function resetTextContent(domElement: Instance): void {
export function resetTextContent(domElement: DOMInstance): void {
setTextContent(domElement, '');
}

Expand All @@ -411,15 +411,15 @@ export function commitTextUpdate(
}

export function appendChild(
parentInstance: Instance,
child: Instance | TextInstance,
parentInstance: DOMInstance,
child: DOMInstance | TextInstance,
): void {
parentInstance.appendChild(child);
}

export function appendChildToContainer(
container: DOMContainer,
child: Instance | TextInstance,
container: DOMInstance,
child: DOMInstance | TextInstance,
): void {
let parentNode;
if (container.nodeType === COMMENT_NODE) {
Expand Down Expand Up @@ -448,17 +448,17 @@ export function appendChildToContainer(
}

export function insertBefore(
parentInstance: Instance,
child: Instance | TextInstance,
beforeChild: Instance | TextInstance | SuspenseInstance,
parentInstance: DOMContainer,
child: DOMInstance | TextInstance,
beforeChild: DOMInstance | TextInstance | SuspenseInstance,
): void {
parentInstance.insertBefore(child, beforeChild);
}

export function insertInContainerBefore(
container: Container,
child: Instance | TextInstance,
beforeChild: Instance | TextInstance | SuspenseInstance,
container: DOMContainer,
child: DOMInstance | TextInstance,
beforeChild: DOMInstance | TextInstance | SuspenseInstance,
): void {
if (container.nodeType === COMMENT_NODE) {
(container.parentNode: any).insertBefore(child, beforeChild);
Expand Down Expand Up @@ -587,7 +587,7 @@ export function clearSuspenseBoundaryFromContainer(
export function hideInstance(instance: Instance): void {
// TODO: Does this work for all element types? What about MathML? Should we
// pass host context to this method?
instance = ((instance: any): HTMLElement);
instance = ((instance: any): DOMHTMLInstance);
const style = instance.style;
if (typeof style.setProperty === 'function') {
style.setProperty('display', 'none', 'important');
Expand All @@ -601,7 +601,7 @@ export function hideTextInstance(textInstance: TextInstance): void {
}

export function unhideInstance(instance: Instance, props: Props): void {
instance = ((instance: any): HTMLElement);
instance = ((instance: any): DOMHTMLInstance);
const styleProp = props[STYLE];
const display =
styleProp !== undefined &&
Expand Down
6 changes: 3 additions & 3 deletions packages/react-native-renderer/src/ReactNativeHostConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -289,12 +289,12 @@ export function appendChild(
}

export function appendChildToContainer(
parentInstance: Container,
parentInstance: Instance | Container,
child: Instance | TextInstance,
): void {
const childTag = typeof child === 'number' ? child : child._nativeTag;
UIManager.setChildren(
parentInstance, // containerTag
((parentInstance: any): Container), // containerTag
[childTag], // reactTags
);
}
Expand Down Expand Up @@ -386,7 +386,7 @@ export function insertBefore(
}

export function insertInContainerBefore(
parentInstance: Container,
parentInstance: Instance | Container,
child: Instance | TextInstance,
beforeChild: Instance | TextInstance,
): void {
Expand Down
67 changes: 34 additions & 33 deletions packages/react-reconciler/src/ReactFiberCommitWork.js
Original file line number Diff line number Diff line change
Expand Up @@ -1099,44 +1099,45 @@ function commitPlacement(finishedWork: Fiber): void {
const before = getHostSibling(finishedWork);
// We only have the top Fiber that was inserted but we need to recurse down its
// children to find all the terminal nodes.
let node: Fiber = finishedWork;
while (true) {
const isHost = node.tag === HostComponent || node.tag === HostText;
if (isHost || (enableFundamentalAPI && node.tag === FundamentalComponent)) {
const stateNode = isHost ? node.stateNode : node.stateNode.instance;
if (before) {
if (isContainer) {
insertInContainerBefore(parent, stateNode, before);
} else {
insertBefore(parent, stateNode, before);
}
insertOrAppendPlacementNode(finishedWork, before, parent, isContainer);
}

function insertOrAppendPlacementNode(
node: Fiber,
before: ?Instance,
parent: Instance,
isContainer: boolean,
): void {
const isHost = node.tag === HostComponent || node.tag === HostText;
if (isHost || (enableFundamentalAPI && node.tag === FundamentalComponent)) {
const stateNode = isHost ? node.stateNode : node.stateNode.instance;
if (before) {
if (isContainer) {
insertInContainerBefore(parent, stateNode, before);
} else {
if (isContainer) {
appendChildToContainer(parent, stateNode);
} else {
appendChild(parent, stateNode);
}
insertBefore(parent, stateNode, before);
}
} else {
if (isContainer) {
appendChildToContainer(parent, stateNode);
} else {
appendChild(parent, stateNode);
}
} else if (node.tag === HostPortal) {
// If the insertion itself is a portal, then we don't want to traverse
// down its children. Instead, we'll get insertions from each child in
// the portal directly.
} else if (node.child !== null) {
node.child.return = node;
node = node.child;
continue;
}
if (node === finishedWork) {
return;
}
while (node.sibling === null) {
if (node.return === null || node.return === finishedWork) {
return;
} else if (node.tag === HostPortal) {
// If the insertion itself is a portal, then we don't want to traverse
// down its children. Instead, we'll get insertions from each child in
// the portal directly.
} else {
const child = node.child;
if (child !== null) {
insertOrAppendPlacementNode(child, before, parent, isContainer);
let sibling = child.sibling;
while (sibling !== null) {
insertOrAppendPlacementNode(sibling, before, parent, isContainer);
sibling = sibling.sibling;
}
node = node.return;
}
node.sibling.return = node.return;
node = node.sibling;
}
}

Expand Down

0 comments on commit 513c18b

Please sign in to comment.