-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Expand file tree
/
Copy pathuseScrollState.ts
More file actions
66 lines (50 loc) · 1.83 KB
/
useScrollState.ts
File metadata and controls
66 lines (50 loc) · 1.83 KB
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
import { useCallback, useSyncExternalStore } from 'react';
import { abs } from '../utils';
interface ScrollState {
readonly scrollTop: number;
readonly scrollLeft: number;
}
const initialScrollState: ScrollState = {
scrollTop: 0,
scrollLeft: 0
};
function getServerSnapshot() {
return initialScrollState;
}
const scrollStateMap = new WeakMap<React.RefObject<HTMLDivElement | null>, ScrollState>();
export function useScrollState(gridRef: React.RefObject<HTMLDivElement | null>): ScrollState {
const subscribe = useCallback(
(onStoreChange: () => void) => {
if (gridRef.current === null) return () => {};
const el = gridRef.current;
// prime the scroll state map with the initial values
setScrollState();
function setScrollState() {
const { scrollTop } = el;
// scrollLeft is negative when direction is rtl
const scrollLeft = abs(el.scrollLeft);
const prev = scrollStateMap.get(gridRef) ?? initialScrollState;
if (prev.scrollTop === scrollTop && prev.scrollLeft === scrollLeft) {
return false;
}
scrollStateMap.set(gridRef, { scrollTop, scrollLeft });
return true;
}
function onScroll() {
if (setScrollState()) {
onStoreChange();
}
}
el.addEventListener('scroll', onScroll);
return () => el.removeEventListener('scroll', onScroll);
},
[gridRef]
);
const getSnapshot = useCallback((): ScrollState => {
// gridRef.current is null during initial render, suspending, or <Activity mode="hidden">
// to avoid returning a different state in those cases,
// we key the ref object instead of the element itself
return scrollStateMap.get(gridRef) ?? initialScrollState;
}, [gridRef]);
return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
}