({
threshold,
delay,
trackVisibility,
rootMargin,
root,
triggerOnce,
skip,
initialInView,
fallbackInView,
onChange,
}: IntersectionOptions = {})
| 34 | * ``` |
| 35 | */ |
| 36 | export function useInView({ |
| 37 | threshold, |
| 38 | delay, |
| 39 | trackVisibility, |
| 40 | rootMargin, |
| 41 | root, |
| 42 | triggerOnce, |
| 43 | skip, |
| 44 | initialInView, |
| 45 | fallbackInView, |
| 46 | onChange, |
| 47 | }: IntersectionOptions = {}): InViewHookResponse { |
| 48 | const [ref, setRef] = React.useState<Element | null>(null); |
| 49 | const callback = React.useRef<IntersectionOptions["onChange"]>(onChange); |
| 50 | const lastInViewRef = React.useRef<boolean | undefined>(initialInView); |
| 51 | const [state, setState] = React.useState<State>({ |
| 52 | inView: !!initialInView, |
| 53 | entry: undefined, |
| 54 | }); |
| 55 | |
| 56 | // Store the onChange callback in a `ref`, so we can access the latest instance |
| 57 | // inside the `useEffect`, but without triggering a rerender. |
| 58 | callback.current = onChange; |
| 59 | |
| 60 | // biome-ignore lint/correctness/useExhaustiveDependencies: threshold is not correctly detected as a dependency |
| 61 | React.useEffect( |
| 62 | () => { |
| 63 | if (lastInViewRef.current === undefined) { |
| 64 | lastInViewRef.current = initialInView; |
| 65 | } |
| 66 | // Ensure we have node ref, and that we shouldn't skip observing |
| 67 | if (skip || !ref) return; |
| 68 | |
| 69 | let unobserve: (() => void) | undefined; |
| 70 | unobserve = observe( |
| 71 | ref, |
| 72 | (inView, entry) => { |
| 73 | const previousInView = lastInViewRef.current; |
| 74 | lastInViewRef.current = inView; |
| 75 | |
| 76 | // Ignore the very first `false` notification so consumers only hear about actual state changes. |
| 77 | if (previousInView === undefined && !inView) { |
| 78 | return; |
| 79 | } |
| 80 | |
| 81 | setState({ |
| 82 | inView, |
| 83 | entry, |
| 84 | }); |
| 85 | if (callback.current) callback.current(inView, entry); |
| 86 | |
| 87 | if (entry.isIntersecting && triggerOnce && unobserve) { |
| 88 | // If it should only trigger once, unobserve the element after it's inView |
| 89 | unobserve(); |
| 90 | unobserve = undefined; |
| 91 | } |
| 92 | }, |
| 93 | { |
searching dependent graphs…