[Perf] useSharedIntersectionObserver: Consider heavy animation
This commit is contained in:
parent
7634094883
commit
94a9f7eba8
@ -1,9 +1,9 @@
|
||||
import { useEffect } from '../lib/teact/teact';
|
||||
import { getIsHeavyAnimating, useEffect } from '../lib/teact/teact';
|
||||
|
||||
import type { CallbackManager } from '../util/callbacks';
|
||||
|
||||
import { createCallbackManager } from '../util/callbacks';
|
||||
import { useStateRef } from './useStateRef';
|
||||
import useLastCallback from './useLastCallback';
|
||||
|
||||
const elementObserverMap = new Map<HTMLElement, [IntersectionObserver, CallbackManager]>();
|
||||
|
||||
@ -12,7 +12,7 @@ export default function useSharedIntersectionObserver(
|
||||
onIntersectionChange: (entry: IntersectionObserverEntry) => void,
|
||||
isDisabled = false,
|
||||
) {
|
||||
const onIntersectionChangeRef = useStateRef(onIntersectionChange);
|
||||
const onIntersectionChangeLast = useLastCallback(onIntersectionChange);
|
||||
|
||||
useEffect(() => {
|
||||
const el = refOrElement && 'current' in refOrElement ? refOrElement.current : refOrElement;
|
||||
@ -20,13 +20,29 @@ export default function useSharedIntersectionObserver(
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const callback: IntersectionObserverCallback = ([entry]) => {
|
||||
// Ignore updates when element is not properly mounted (`display: none`)
|
||||
if (!(entry.target as HTMLElement).offsetWidth || !(entry.target as HTMLElement).offsetHeight) {
|
||||
return;
|
||||
const entriesAccumulator = new Map<Element, IntersectionObserverEntry>();
|
||||
|
||||
function flush() {
|
||||
for (const entry of entriesAccumulator.values()) {
|
||||
// Ignore updates when element is not properly mounted (`display: none`)
|
||||
if (!(entry.target as HTMLElement).offsetParent) {
|
||||
continue;
|
||||
}
|
||||
|
||||
onIntersectionChangeLast(entry);
|
||||
}
|
||||
|
||||
onIntersectionChangeRef.current(entry);
|
||||
entriesAccumulator.clear();
|
||||
}
|
||||
|
||||
const callback: IntersectionObserverCallback = ([entry]) => {
|
||||
entriesAccumulator.set(entry.target, entry);
|
||||
|
||||
if (!getIsHeavyAnimating()) {
|
||||
flush();
|
||||
} else {
|
||||
getIsHeavyAnimating.once(flush);
|
||||
}
|
||||
};
|
||||
|
||||
let [observer, callbackManager] = elementObserverMap.get(el) || [undefined, undefined];
|
||||
@ -46,5 +62,5 @@ export default function useSharedIntersectionObserver(
|
||||
elementObserverMap.delete(el);
|
||||
}
|
||||
};
|
||||
}, [isDisabled, onIntersectionChangeRef, refOrElement]);
|
||||
}, [isDisabled, refOrElement]);
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ const SIGNAL_MARK = Symbol('SIGNAL_MARK');
|
||||
export type Signal<T = any> = ((() => T) & {
|
||||
readonly [SIGNAL_MARK]: symbol;
|
||||
subscribe: (cb: AnyToVoidFunction) => NoneToVoidFunction;
|
||||
once: (cb: AnyToVoidFunction) => NoneToVoidFunction;
|
||||
});
|
||||
|
||||
export type SignalSetter = (newValue: any) => void;
|
||||
@ -51,6 +52,15 @@ export function createSignal<T>(defaultValue?: T) {
|
||||
};
|
||||
}
|
||||
|
||||
function once(effect: NoneToVoidFunction) {
|
||||
const unsub = subscribe(() => {
|
||||
unsub();
|
||||
effect();
|
||||
});
|
||||
|
||||
return unsub;
|
||||
}
|
||||
|
||||
function getter() {
|
||||
if (currentEffect) {
|
||||
subscribe(currentEffect);
|
||||
@ -71,6 +81,7 @@ export function createSignal<T>(defaultValue?: T) {
|
||||
const signal = Object.assign(getter as Signal<T>, {
|
||||
[SIGNAL_MARK]: SIGNAL_MARK,
|
||||
subscribe,
|
||||
once,
|
||||
});
|
||||
|
||||
return [signal, setter] as const;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user