-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathindex.ts
81 lines (66 loc) · 1.9 KB
/
index.ts
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
import { useRef, useState, useEffect } from 'react';
import shallowEqual from 'shallowequal';
export type IntersectionChangeHandler = (entry: IntersectionObserverEntry) => void;
export type IntersectionOptions = {
root?: React.RefObject<Element>;
rootMargin?: string;
threshold?: number | number[];
once?: boolean;
defaultIntersecting?: boolean;
};
export const useIntersection = (
target: React.RefObject<Element> | Element | null,
options: IntersectionOptions = {},
callback?: IntersectionChangeHandler,
) => {
const { defaultIntersecting, once, ...opts } = options;
const optsRef = useRef(opts);
const [intersecting, setIntersecting] = useState(defaultIntersecting === true);
const intersectedRef = useRef(false);
useEffect(() => {
if (!shallowEqual(optsRef.current, opts)) {
optsRef.current = opts;
}
});
useEffect(() => {
if (target == null) {
return;
}
const element = target instanceof Element ? target : target.current;
if (element == null) {
return;
}
if (once && intersectedRef.current) {
return;
}
const observer = new IntersectionObserver(
(entries) => {
const entry = entries[entries.length - 1];
setIntersecting(entry.isIntersecting);
if (callback != null) {
callback(entry);
}
if (entry.isIntersecting) {
intersectedRef.current = true;
}
if (once && entry.isIntersecting && element != null) {
observer.unobserve(element);
}
},
{
...optsRef.current,
root: optsRef.current.root != null ? optsRef.current.root.current : null,
},
);
observer.observe(element);
return () => {
if (once && intersectedRef.current) {
return;
}
if (element != null) {
observer.unobserve(element);
}
};
}, [optsRef.current, target]);
return intersecting;
};