-
Notifications
You must be signed in to change notification settings - Fork 190
Expand file tree
/
Copy pathuseInView.tsx
More file actions
99 lines (89 loc) · 2.61 KB
/
useInView.tsx
File metadata and controls
99 lines (89 loc) · 2.61 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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import * as React from "react";
import type { IntersectionOptions, InViewHookResponse } from "./index";
import { supportsRefCleanup } from "./reactVersion";
import { useOnInView } from "./useOnInView";
type State = {
inView: boolean;
entry?: IntersectionObserverEntry;
};
/**
* React Hooks make it easy to monitor the `inView` state of your components. Call
* the `useInView` hook with the (optional) [options](#options) you need. It will
* return an array containing a `ref`, the `inView` status and the current
* [`entry`](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry).
* Assign the `ref` to the DOM element you want to monitor, and the hook will
* report the status.
*
* @example
* ```jsx
* import React from 'react';
* import { useInView } from 'react-intersection-observer';
*
* const Component = () => {
* const { ref, inView, entry } = useInView({
* threshold: 0,
* });
*
* return (
* <div ref={ref}>
* <h2>{`Header inside viewport ${inView}.`}</h2>
* </div>
* );
* };
* ```
*/
export function useInView(
options: IntersectionOptions = {},
): InViewHookResponse {
const [state, setState] = React.useState<State>({
inView: !!options.initialInView,
entry: undefined,
});
const optionsRef = React.useRef(options);
optionsRef.current = options;
const entryTargetRef = React.useRef<Element | undefined>(undefined);
const inViewRef = useOnInView((inView, entry) => {
entryTargetRef.current = entry.target;
setState({ inView, entry });
if (optionsRef.current.onChange) {
optionsRef.current.onChange(inView, entry);
}
}, options);
const refCallback = React.useCallback(
(node: Element | null) => {
const resetIfNeeded = () => {
const {
skip,
triggerOnce,
initialInView: latestInitialInView,
} = optionsRef.current;
if (!skip && !triggerOnce && entryTargetRef.current) {
setState({
inView: !!latestInitialInView,
entry: undefined,
});
entryTargetRef.current = undefined;
}
};
const cleanup = inViewRef(node);
if (!node) {
resetIfNeeded();
return;
}
if (!supportsRefCleanup) {
return;
}
return () => {
cleanup?.();
resetIfNeeded();
};
},
[inViewRef],
);
const result = [refCallback, state.inView, state.entry] as InViewHookResponse;
// Support object destructuring, by adding the specific values.
result.ref = result[0];
result.inView = result[1];
result.entry = result[2];
return result;
}