[Perf] Teact: Some minor optimizations

This commit is contained in:
Alexander Zinchuk 2022-02-02 22:48:12 +01:00
parent 51b2893b39
commit 1f1c30fd0f

View File

@ -76,18 +76,20 @@ function renderWithVirtual(
moveDirection?: 'up' | 'down'; moveDirection?: 'up' | 'down';
} = {}, } = {},
) { ) {
const isCurrentComponent = $current && isComponentElement($current);
const isNewComponent = $new && isComponentElement($new);
if ( if (
!skipComponentUpdate !skipComponentUpdate
&& $current && $new && isCurrentComponent && isNewComponent
&& isComponentElement($current) && isComponentElement($new) && !hasElementChanged($current!, $new!)
&& !hasElementChanged($current, $new)
) { ) {
$new = updateComponent($current, $new); $new = updateComponent($current as VirtualElementComponent, $new as VirtualElementComponent);
} }
// Parent element may have changed, so we need to update the listener closure. // Parent element may have changed, so we need to update the listener closure.
if (!skipComponentUpdate && $new && isComponentElement($new) && $new.componentInstance.isMounted) { if (!skipComponentUpdate && isNewComponent && ($new as VirtualElementComponent).componentInstance.isMounted) {
setupComponentUpdateListener($new, $parent, index, parentEl); setupComponentUpdateListener($new as VirtualElementComponent, $parent, index, parentEl);
} }
if ($current === $new) { if ($current === $new) {
@ -95,8 +97,8 @@ function renderWithVirtual(
} }
if (!$current && $new) { if (!$current && $new) {
if (isComponentElement($new)) { if (isNewComponent) {
$new = initComponent($new, $parent, index, parentEl); $new = initComponent($new as VirtualElementComponent, $parent, index, parentEl);
} }
const node = createNode($new); const node = createNode($new);
@ -112,8 +114,8 @@ function renderWithVirtual(
unmountTree($current); unmountTree($current);
} else if ($current && $new) { } else if ($current && $new) {
if (hasElementChanged($current, $new)) { if (hasElementChanged($current, $new)) {
if (isComponentElement($new)) { if (isNewComponent) {
$new = initComponent($new, $parent, index, parentEl); $new = initComponent($new as VirtualElementComponent, $parent, index, parentEl);
} }
const node = createNode($new); const node = createNode($new);
@ -121,7 +123,7 @@ function renderWithVirtual(
parentEl.replaceChild(node, getTarget($current)!); parentEl.replaceChild(node, getTarget($current)!);
unmountTree($current); unmountTree($current);
} else { } else {
const areComponents = isComponentElement($current) && isComponentElement($new); const areComponents = isCurrentComponent && isNewComponent;
const currentTarget = getTarget($current); const currentTarget = getTarget($current);
if (!areComponents) { if (!areComponents) {
@ -133,7 +135,7 @@ function renderWithVirtual(
} }
} }
if (isRealElement($current) && isRealElement($new)) { if (isRealElement($new)) {
if (moveDirection) { if (moveDirection) {
const node = currentTarget!; const node = currentTarget!;
const nextSibling = parentEl.childNodes[moveDirection === 'up' ? index : index + 1]; const nextSibling = parentEl.childNodes[moveDirection === 'up' ? index : index + 1];
@ -146,11 +148,11 @@ function renderWithVirtual(
} }
if (!areComponents) { if (!areComponents) {
updateAttributes($current, $new, currentTarget as HTMLElement); updateAttributes(($current as VirtualRealElement), $new, currentTarget as HTMLElement);
} }
$new.children = renderChildren( $new.children = renderChildren(
$current, ($current as VirtualRealElement),
$new, $new,
areComponents ? parentEl : currentTarget as HTMLElement, areComponents ? parentEl : currentTarget as HTMLElement,
); );
@ -228,9 +230,9 @@ function createNode($element: VirtualElement): Node {
props.ref.current = element; props.ref.current = element;
} }
Object.keys(props).forEach((key) => { Object.entries(props).forEach(([key, value]) => {
if (props[key] !== undefined) { if (props[key] !== undefined) {
setAttribute(element, key, props[key]); setAttribute(element, key, value);
} }
}); });
@ -248,9 +250,11 @@ function renderChildren(
return renderFastListChildren($current, $new, currentEl); return renderFastListChildren($current, $new, currentEl);
} }
const maxLength = Math.max($current.children.length, $new.children.length); const currentChildrenLength = $current.children.length;
const newChildrenLength = $new.children.length;
const maxLength = Math.max(currentChildrenLength, newChildrenLength);
const newChildren = []; const newChildren = [];
const fragment = $new.children.length > $current.children.length + 1 ? document.createDocumentFragment() : undefined; const fragment = newChildrenLength > currentChildrenLength + 1 ? document.createDocumentFragment() : undefined;
for (let i = 0; i < maxLength; i++) { for (let i = 0; i < maxLength; i++) {
const $newChild = renderWithVirtual( const $newChild = renderWithVirtual(
@ -259,7 +263,7 @@ function renderChildren(
$new.children[i], $new.children[i],
$new, $new,
i, i,
i >= $current.children.length ? { fragment } : undefined, i >= currentChildrenLength ? { fragment } : undefined,
); );
if ($newChild) { if ($newChild) {
@ -364,9 +368,7 @@ function renderFastListChildren($current: VirtualRealElement, $new: VirtualRealE
newChildren.push( newChildren.push(
renderWithVirtual(currentEl, currentChildInfo.$element, $newChild, $new, i, { renderWithVirtual(currentEl, currentChildInfo.$element, $newChild, $new, i, {
forceIndex: true, forceIndex: true,
...(shouldMoveNode && { moveDirection: shouldMoveNode ? (isMovingDown ? 'down' : 'up') : undefined,
moveDirection: isMovingDown ? 'down' : 'up',
}),
})!, })!,
); );
}); });
@ -402,11 +404,10 @@ function flushFragmentQueue(
} }
function updateAttributes($current: VirtualRealElement, $new: VirtualRealElement, element: HTMLElement) { function updateAttributes($current: VirtualRealElement, $new: VirtualRealElement, element: HTMLElement) {
const currentKeys = Object.keys($current.props); const currentEntries = Object.entries($current.props);
const newKeys = Object.keys($new.props); const newEntries = Object.entries($new.props);
currentKeys.forEach((key) => { currentEntries.forEach(([key, currentValue]) => {
const currentValue = $current.props[key];
const newValue = $new.props[key]; const newValue = $new.props[key];
if ( if (
@ -420,9 +421,8 @@ function updateAttributes($current: VirtualRealElement, $new: VirtualRealElement
} }
}); });
newKeys.forEach((key) => { newEntries.forEach(([key, newValue]) => {
const currentValue = $current.props[key]; const currentValue = $current.props[key];
const newValue = $new.props[key];
if (newValue !== undefined && newValue !== currentValue) { if (newValue !== undefined && newValue !== currentValue) {
setAttribute(element, key, newValue); setAttribute(element, key, newValue);