Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | 4x 4x 4x 4x 39x 4x 45x 45x 45x 7x 7x 7x 7x 7x 45x 30x 18x 12x 12x 606x 606x 606x 606x 606x 6x 6x 606x 600x 600x 12x 12x 12x 6x 12x 12x 1x 45x 4x | import React, { useCallback, useEffect, useRef } from "react";
const scrollCache: Record<string, number> = {};
const MAX_SCROLL_RESTORE_FRAMES = 600;
export const getCachedScrollPosition = (cacheKey: string | undefined) =>
cacheKey ? scrollCache[cacheKey] : undefined;
const useCachedScroll = (
cacheKey: string | undefined,
scrollElement: HTMLDivElement | null,
restoreScroll = true,
) => {
const programmaticScrollPosition = useRef<number | null>(null);
const isUserScrolling = useRef(false);
const onScroll = useCallback<React.UIEventHandler<HTMLDivElement>>(
(e) => {
Iif (!cacheKey) {
return;
}
Iif (e.currentTarget.scrollTop === programmaticScrollPosition.current) {
programmaticScrollPosition.current = null;
return;
}
programmaticScrollPosition.current = null;
scrollCache[cacheKey] = e.currentTarget.scrollTop;
isUserScrolling.current = true;
},
[cacheKey],
);
useEffect(() => {
if (!cacheKey || !scrollElement || !restoreScroll) {
return;
}
let animationFrameId: number | undefined;
let restoreFrames = 0;
const checkScroll = () => {
const savedPosition = scrollCache[cacheKey] ?? 0;
Iif (isUserScrolling.current) {
return;
}
const maxScrollTop = Math.max(
0,
scrollElement.scrollHeight - scrollElement.clientHeight,
);
const targetScrollTop = Math.min(savedPosition, maxScrollTop);
if (scrollElement.scrollTop !== targetScrollTop) {
scrollElement.scrollTop = targetScrollTop;
programmaticScrollPosition.current = scrollElement.scrollTop;
}
if (
scrollElement.scrollTop < savedPosition &&
restoreFrames < MAX_SCROLL_RESTORE_FRAMES
) {
restoreFrames += 1;
animationFrameId = requestAnimationFrame(checkScroll);
}
};
const savedPosition = scrollCache[cacheKey] ?? 0;
isUserScrolling.current = false;
if (savedPosition > 0) {
checkScroll();
}
return () => {
if (animationFrameId !== undefined) {
cancelAnimationFrame(animationFrameId);
}
};
}, [cacheKey, restoreScroll, scrollElement]);
return { onScroll } as const;
};
export default useCachedScroll;
|