Teact: Disable setting state on unmounted components
This commit is contained in:
parent
af973d6f20
commit
8cdc1b87be
@ -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<T extends VirtualElement | undefined>(
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
@ -57,6 +57,12 @@ export interface VirtualElementFragment {
|
||||
|
||||
export type StateHookSetter<T> = (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<T>(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;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user