-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathuse-intersection-observer.ts
60 lines (52 loc) · 1.53 KB
/
use-intersection-observer.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
"use client";
import { useCallback, useRef, useState } from "react";
export interface UseIntersectionObserverOptions {
rootMargin?: string;
root?: null | Element;
threshold?: number | number[];
}
/**
* Courtesy of {@link https://usehooks.com/useintersectionobserver}
*
* @param options - The options to pass to the IntersectionObserver
*
* @returns A tuple containing a ref to attach to the element to observe and the IntersectionObserverEntry
*
* @example
* const [ref, entry] = useIntersectionObserver({
* threshold: 0.5,
* rootMargin: "0px",
* root: null,
* });
*
* <div ref={ref}>
* {entry?.isIntersecting ? "Visible" : "Not visible"}
* </div>
*/
export function useIntersectionObserver(
options?: UseIntersectionObserverOptions,
) {
const { root = null, threshold = 1, rootMargin = "0px" } = options || {};
const [entry, setEntry] = useState<IntersectionObserverEntry>();
const previousObserver = useRef<IntersectionObserver>(undefined);
const customRef = useCallback(
(node: Element) => {
if (previousObserver.current) {
previousObserver.current.disconnect();
previousObserver.current = undefined;
}
if (node?.nodeType === Node.ELEMENT_NODE) {
const observer = new IntersectionObserver(
([entry]) => {
setEntry(entry);
},
{ root, threshold, rootMargin },
);
observer.observe(node);
previousObserver.current = observer;
}
},
[threshold, root, rootMargin],
);
return [customRef, entry];
}