diff --git a/src/lib/teact/teact.ts b/src/lib/teact/teact.ts index ba3c6625e..c9228dac6 100644 --- a/src/lib/teact/teact.ts +++ b/src/lib/teact/teact.ts @@ -1,11 +1,10 @@ import type { ReactElement } from 'react'; import { DEBUG, DEBUG_MORE } from '../../config'; import { - fastRafWithFallback, - fastRafPrimaryWithFallback, - onTickEnd, - onTickEndPrimary, throttleWithRafFallback, + throttleWithPrimaryRafFallback, + throttleWithTickEnd, + throttleWithPrimaryTickEnd, } from '../../util/schedulers'; import { orderBy } from '../../util/iteratees'; import { getUnequalProps } from '../../util/arePropsShallowEqual'; @@ -15,7 +14,9 @@ import { incrementOverlayCounter } from '../../util/debugOverlay'; export type Props = AnyLiteral; export type FC

= (props: P) => any; // eslint-disable-next-line @typescript-eslint/naming-convention -export type FC_withDebug = FC & { DEBUG_contentComponentName?: string }; +export type FC_withDebug = + FC + & { DEBUG_contentComponentName?: string }; export enum VirtualElementTypesEnum { Empty, @@ -79,9 +80,8 @@ interface ComponentInstance { effects: { cursor: number; byCursor: { - effect: () => void; dependencies?: readonly any[]; - cleanup?: Function; + cleanup?: NoneToVoidFunction; }[]; }; memos: { @@ -455,8 +455,7 @@ export function unmountComponent(componentInstance: ComponentInstance) { // We need to remove all references to DOM objects. We also clean all other references, just in case function helpGc(componentInstance: ComponentInstance) { componentInstance.hooks.effects.byCursor.forEach((hook) => { - hook.cleanup = undefined; - hook.effect = undefined as any; + hook.cleanup = undefined as any; hook.dependencies = undefined; }); @@ -554,10 +553,10 @@ export function useState(initial?: T, debugKey?: string): [T, StateHookSetter ]; } -function useLayoutEffectBase( - schedulerFn: typeof onTickEnd | typeof requestAnimationFrame, - primarySchedulerFn: typeof onTickEnd | typeof requestAnimationFrame, - effect: () => Function | void, +function useEffectBase( + schedulerFn: (cb: NoneToVoidFunction) => void, + primarySchedulerFn: (cb: NoneToVoidFunction) => void, + effect: () => NoneToVoidFunction | void, dependencies?: readonly any[], debugKey?: string, ) { @@ -636,7 +635,12 @@ function useLayoutEffectBase( } } - if (byCursor[cursor] !== undefined && dependencies && byCursor[cursor].dependencies) { + function schedule() { + primarySchedulerFn(execCleanup); + schedulerFn(exec); + } + + if (dependencies && byCursor[cursor]?.dependencies) { if (dependencies.some((dependency, i) => dependency !== byCursor[cursor].dependencies![i])) { if (debugKey) { const causedBy = dependencies.reduce((res, newValue, i) => { @@ -652,8 +656,7 @@ function useLayoutEffectBase( console.log(`[Teact] Effect "${debugKey}" caused by dependencies.`, causedBy.join(', ')); } - primarySchedulerFn(execCleanup); - schedulerFn(exec); + schedule(); } } else { if (debugKey) { @@ -661,25 +664,37 @@ function useLayoutEffectBase( console.log(`[Teact] Effect "${debugKey}" caused by missing dependencies.`); } - primarySchedulerFn(execCleanup); - schedulerFn(exec); + schedule(); } byCursor[cursor] = { - effect, + ...byCursor[cursor], dependencies, - cleanup: byCursor[cursor]?.cleanup, }; renderingInstance.hooks.effects.cursor++; } -export function useEffect(effect: () => Function | void, dependencies?: readonly any[], debugKey?: string) { - return useLayoutEffectBase(fastRafWithFallback, fastRafPrimaryWithFallback, effect, dependencies, debugKey); +export function useEffect( + effect: () => NoneToVoidFunction | void, + dependencies?: readonly any[], + debugKey?: string, +) { + const schedulerFn = useMemo(() => throttleWithRafFallback((cb: NoneToVoidFunction) => cb()), []); + const primarySchedulerFn = useMemo(() => throttleWithPrimaryRafFallback((cb: NoneToVoidFunction) => cb()), []); + + return useEffectBase(schedulerFn, primarySchedulerFn, effect, dependencies, debugKey); } -export function useLayoutEffect(effect: () => Function | void, dependencies?: readonly any[], debugKey?: string) { - return useLayoutEffectBase(onTickEnd, onTickEndPrimary, effect, dependencies, debugKey); +export function useLayoutEffect( + effect: () => NoneToVoidFunction | void, + dependencies?: readonly any[], + debugKey?: string, +) { + const schedulerFn = useMemo(() => throttleWithTickEnd((cb: NoneToVoidFunction) => cb()), []); + const primarySchedulerFn = useMemo(() => throttleWithPrimaryTickEnd((cb: NoneToVoidFunction) => cb()), []); + + return useEffectBase(schedulerFn, primarySchedulerFn, effect, dependencies, debugKey); } export function useMemo(resolver: () => T, dependencies: any[], debugKey?: string): T { diff --git a/src/util/schedulers.ts b/src/util/schedulers.ts index 5b47b740f..4b2c7f9be 100644 --- a/src/util/schedulers.ts +++ b/src/util/schedulers.ts @@ -92,6 +92,10 @@ export function throttleWithTickEnd(fn: F) { return throttleWith(onTickEnd, fn); } +export function throttleWithPrimaryTickEnd(fn: F) { + return throttleWith(onTickEndPrimary, fn); +} + export function throttleWith(schedulerFn: Scheduler, fn: F) { let waiting = false; let args: Parameters;