diff --git a/src/lib/teact/teact-dom.ts b/src/lib/teact/teact-dom.ts index 35f401ccc..0d3a67677 100644 --- a/src/lib/teact/teact-dom.ts +++ b/src/lib/teact/teact-dom.ts @@ -1,24 +1,25 @@ import type { VirtualElement, - VirtualElementComponent, - VirtualElementTag, - VirtualElementParent, VirtualElementChildren, - VirtualElementReal, + VirtualElementComponent, VirtualElementFragment, + VirtualElementParent, + VirtualElementReal, + VirtualElementTag, } from './teact'; import { + captureImmediateEffects, hasElementChanged, isComponentElement, - isTagElement, - isParentElement, - isTextElement, isEmptyElement, + isFragmentElement, + isParentElement, + isTagElement, + isTextElement, mountComponent, + MountState, renderComponent, unmountComponent, - isFragmentElement, - captureImmediateEffects, } from './teact'; import { DEBUG } from '../../config'; import { addEventListener, removeAllDelegatedListeners, removeEventListener } from './dom-events'; @@ -103,7 +104,11 @@ function renderWithVirtual( } // Parent element may have changed, so we need to update the listener closure. - if (!skipComponentUpdate && isNewComponent && ($new as VirtualElementComponent).componentInstance.isMounted) { + if ( + !skipComponentUpdate + && isNewComponent + && ($new as VirtualElementComponent).componentInstance.mountState === MountState.Mounted + ) { setupComponentUpdateListener(parentEl, $new as VirtualElementComponent, $parent, index); } @@ -211,7 +216,7 @@ function initComponent( ) { const { componentInstance } = $element; - if (!componentInstance.isMounted) { + if (componentInstance.mountState === MountState.New) { $element = mountComponent(componentInstance); setupComponentUpdateListener(parentEl, $element, $parent, index); @@ -219,8 +224,6 @@ function initComponent( if (isComponentElement($firstChild)) { $element.children = [initComponent(parentEl, $firstChild, $element, 0)]; } - - componentInstance.isMounted = true; } return $element; diff --git a/src/lib/teact/teact.ts b/src/lib/teact/teact.ts index 97dcb0bf3..39a2f1e80 100644 --- a/src/lib/teact/teact.ts +++ b/src/lib/teact/teact.ts @@ -57,6 +57,12 @@ export interface VirtualElementFragment { export type StateHookSetter = (newValue: ((current: T) => T) | T) => void; +export enum MountState { + New, + Mounted, + Unmounted, +} + interface ComponentInstance { id: number; $element: VirtualElementComponent; @@ -64,7 +70,7 @@ interface ComponentInstance { name: string; props: Props; renderedValue?: any; - isMounted: boolean; + mountState: MountState; hooks: { state: { cursor: number; @@ -201,7 +207,7 @@ function createComponentInstance(Component: FC, props: Props, children: any[]): ...props, ...(parsedChildren && { children: parsedChildren }), }, - isMounted: false, + mountState: MountState.New, hooks: { state: { cursor: 0, @@ -438,7 +444,7 @@ export function renderComponent(componentInstance: ComponentInstance) { newRenderedValue = componentInstance.renderedValue; }); - if (componentInstance.isMounted && newRenderedValue === componentInstance.renderedValue) { + if (componentInstance.mountState === MountState.Mounted && newRenderedValue === componentInstance.renderedValue) { return componentInstance.$element; } @@ -472,12 +478,12 @@ export function hasElementChanged($old: VirtualElement, $new: VirtualElement) { export function mountComponent(componentInstance: ComponentInstance) { renderComponent(componentInstance); - componentInstance.isMounted = true; + componentInstance.mountState = MountState.Mounted; return componentInstance.$element; } export function unmountComponent(componentInstance: ComponentInstance) { - if (!componentInstance.isMounted) { + if (componentInstance.mountState !== MountState.Mounted) { return; } @@ -492,7 +498,7 @@ export function unmountComponent(componentInstance: ComponentInstance) { effect.releaseSignals?.(); }); - componentInstance.isMounted = false; + componentInstance.mountState = MountState.Unmounted; helpGc(componentInstance); } @@ -530,7 +536,7 @@ function helpGc(componentInstance: ComponentInstance) { } function prepareComponentForFrame(componentInstance: ComponentInstance) { - if (!componentInstance.isMounted) { + if (componentInstance.mountState !== MountState.Mounted) { return; } @@ -540,7 +546,7 @@ function prepareComponentForFrame(componentInstance: ComponentInstance) { } function forceUpdateComponent(componentInstance: ComponentInstance) { - if (!componentInstance.isMounted || !componentInstance.onUpdate) { + if (componentInstance.mountState !== MountState.Mounted || !componentInstance.onUpdate) { return; } @@ -563,6 +569,10 @@ export function useState(initial?: T, debugKey?: string): [T, StateHookSetter value: initial, nextValue: initial, setter: ((componentInstance) => (newValue: ((current: T) => T) | T) => { + if (componentInstance.mountState === MountState.Unmounted) { + return; + } + if (typeof newValue === 'function') { newValue = (newValue as (current: T) => T)(byCursor[cursor].nextValue); } @@ -644,7 +654,7 @@ function useEffectBase( }); const runEffect = () => safeExec(() => { - if (!componentInstance.isMounted) { + if (componentInstance.mountState === MountState.Unmounted) { return; }