Revert "Revert "[Perf] Teact: Performance optimizations""

This reverts commit 1ef9a367504f35f8c86f0865cb25305756a93e3c.
This commit is contained in:
Alexander Zinchuk 2023-07-20 15:57:54 +02:00
parent 2f21b34689
commit 255fb11d94

View File

@ -1,13 +1,13 @@
import type { ReactElement } from 'react'; import type { ReactElement } from 'react';
import { requestMeasure, requestMutation } from '../fasterdom/fasterdom';
import { DEBUG, DEBUG_MORE } from '../../config'; import { DEBUG, DEBUG_MORE } from '../../config';
import { throttleWith } from '../../util/schedulers';
import { orderBy } from '../../util/iteratees';
import { logUnequalProps } from '../../util/arePropsShallowEqual'; import { logUnequalProps } from '../../util/arePropsShallowEqual';
import { incrementOverlayCounter } from '../../util/debugOverlay'; import { incrementOverlayCounter } from '../../util/debugOverlay';
import { isSignal } from '../../util/signals'; import { orderBy } from '../../util/iteratees';
import safeExec from '../../util/safeExec'; import safeExec from '../../util/safeExec';
import { throttleWith } from '../../util/schedulers';
import { isSignal } from '../../util/signals';
import { requestMeasure, requestMutation } from '../fasterdom/fasterdom';
export type Props = AnyLiteral; export type Props = AnyLiteral;
export type FC<P extends Props = any> = (props: P) => any; export type FC<P extends Props = any> = (props: P) => any;
@ -170,8 +170,6 @@ function createElement(
props: Props, props: Props,
...children: any[] ...children: any[]
): VirtualElementParent | VirtualElementChildren { ): VirtualElementParent | VirtualElementChildren {
children = children.flat();
if (source === Fragment) { if (source === Fragment) {
return buildFragmentElement(children); return buildFragmentElement(children);
} else if (typeof source === 'function') { } else if (typeof source === 'function') {
@ -184,18 +182,13 @@ function createElement(
function buildFragmentElement(children: any[]): VirtualElementFragment { function buildFragmentElement(children: any[]): VirtualElementFragment {
return { return {
type: VirtualElementTypesEnum.Fragment, type: VirtualElementTypesEnum.Fragment,
children: dropEmptyTail(children, true).map(buildChildElement), children: buildChildren(children, true),
}; };
} }
function createComponentInstance(Component: FC, props: Props, children: any[]): VirtualElementComponent { function createComponentInstance(Component: FC, props: Props, children: any[]): VirtualElementComponent {
let parsedChildren: any | any[] | undefined; if (children?.length) {
if (children.length === 0) { props.children = children.length === 1 ? children[0] : children;
parsedChildren = undefined;
} else if (children.length === 1) {
[parsedChildren] = children;
} else {
parsedChildren = children;
} }
const componentInstance: ComponentInstance = { const componentInstance: ComponentInstance = {
@ -203,10 +196,7 @@ function createComponentInstance(Component: FC, props: Props, children: any[]):
$element: {} as VirtualElementComponent, $element: {} as VirtualElementComponent,
Component, Component,
name: Component.name, name: Component.name,
props: { props,
...props,
...(parsedChildren && { children: parsedChildren }),
},
mountState: MountState.New, mountState: MountState.New,
hooks: { hooks: {
state: { state: {
@ -235,13 +225,13 @@ function createComponentInstance(Component: FC, props: Props, children: any[]):
function buildComponentElement( function buildComponentElement(
componentInstance: ComponentInstance, componentInstance: ComponentInstance,
children: VirtualElementChildren = [], children?: VirtualElementChildren,
): VirtualElementComponent { ): VirtualElementComponent {
return { return {
type: VirtualElementTypesEnum.Component, type: VirtualElementTypesEnum.Component,
componentInstance, componentInstance,
props: componentInstance.props, props: componentInstance.props,
children: dropEmptyTail(children, true).map(buildChildElement), children: children ? buildChildren(children, true) : [],
}; };
} }
@ -250,10 +240,26 @@ function buildTagElement(tag: string, props: Props, children: any[]): VirtualEle
type: VirtualElementTypesEnum.Tag, type: VirtualElementTypesEnum.Tag,
tag, tag,
props, props,
children: dropEmptyTail(children).map(buildChildElement), children: buildChildren(children),
}; };
} }
function buildChildren(children: any[], noEmpty = false): VirtualElement[] {
const cleanChildren = dropEmptyTail(children, noEmpty);
const newChildren = [];
for (let i = 0, l = cleanChildren.length; i < l; i++) {
const child = cleanChildren[i];
if (Array.isArray(child)) {
newChildren.push(...buildChildren(child, noEmpty));
} else {
newChildren.push(buildChildElement(child));
}
}
return newChildren;
}
// We only need placeholders in the middle of collection (to ensure other elements order). // We only need placeholders in the middle of collection (to ensure other elements order).
function dropEmptyTail(children: any[], noEmpty = false) { function dropEmptyTail(children: any[], noEmpty = false) {
let i = children.length - 1; let i = children.length - 1;
@ -276,31 +282,22 @@ function dropEmptyTail(children: any[], noEmpty = false) {
} }
function isEmptyPlaceholder(child: any) { function isEmptyPlaceholder(child: any) {
// eslint-disable-next-line no-null/no-null return !child && child !== 0;
return child === false || child === null || child === undefined;
} }
function buildChildElement(child: any): VirtualElement { function buildChildElement(child: any): VirtualElement {
if (isEmptyPlaceholder(child)) { if (isEmptyPlaceholder(child)) {
return buildEmptyElement(); return { type: VirtualElementTypesEnum.Empty };
} else if (isParentElement(child)) { } else if (isParentElement(child)) {
return child; return child;
} else { } else {
return buildTextElement(child); return {
type: VirtualElementTypesEnum.Text,
value: String(child),
};
} }
} }
function buildTextElement(value: any): VirtualElementText {
return {
type: VirtualElementTypesEnum.Text,
value: String(value),
};
}
function buildEmptyElement(): VirtualElementEmpty {
return { type: VirtualElementTypesEnum.Empty };
}
// eslint-disable-next-line @typescript-eslint/naming-convention // eslint-disable-next-line @typescript-eslint/naming-convention
const DEBUG_components: AnyLiteral = { TOTAL: { name: 'TOTAL', renders: 0 } }; const DEBUG_components: AnyLiteral = { TOTAL: { name: 'TOTAL', renders: 0 } };
// eslint-disable-next-line @typescript-eslint/naming-convention // eslint-disable-next-line @typescript-eslint/naming-convention
@ -584,12 +581,13 @@ export function useState<T>(): [T | undefined, StateHookSetter<T | undefined>];
export function useState<T>(initial: T, debugKey?: string): [T, StateHookSetter<T>]; export function useState<T>(initial: T, debugKey?: string): [T, StateHookSetter<T>];
export function useState<T>(initial?: T, debugKey?: string): [T, StateHookSetter<T>] { export function useState<T>(initial?: T, debugKey?: string): [T, StateHookSetter<T>] {
const { cursor, byCursor } = renderingInstance.hooks.state; const { cursor, byCursor } = renderingInstance.hooks.state;
const componentInstance = renderingInstance;
if (byCursor[cursor] === undefined) { if (byCursor[cursor] === undefined) {
byCursor[cursor] = { byCursor[cursor] = {
value: initial, value: initial,
nextValue: initial, nextValue: initial,
setter: ((componentInstance) => (newValue: ((current: T) => T) | T) => { setter: (newValue: ((current: T) => T) | T) => {
if (componentInstance.mountState === MountState.Unmounted) { if (componentInstance.mountState === MountState.Unmounted) {
return; return;
} }
@ -616,7 +614,7 @@ export function useState<T>(initial?: T, debugKey?: string): [T, StateHookSetter
byCursor[cursor].nextValue, byCursor[cursor].nextValue,
); );
} }
})(renderingInstance), },
}; };
} }