DeepBrowsingProvider.tsx raw
1 import { createContext, useCallback, useContext, useEffect, useRef, useState } from 'react'
2
3 type TDeepBrowsingContext = {
4 deepBrowsing: boolean
5 lastScrollTop: number
6 }
7
8 const DeepBrowsingContext = createContext<TDeepBrowsingContext | undefined>(undefined)
9
10 export const useDeepBrowsing = () => {
11 const context = useContext(DeepBrowsingContext)
12 if (!context) {
13 throw new Error('useDeepBrowsing must be used within a DeepBrowsingProvider')
14 }
15 return context
16 }
17
18 export function DeepBrowsingProvider({
19 children,
20 active,
21 scrollAreaRef
22 }: {
23 children: React.ReactNode
24 active: boolean
25 scrollAreaRef?: React.RefObject<HTMLDivElement>
26 }) {
27 const [deepBrowsing, setDeepBrowsing] = useState(false)
28 const lastScrollTopRef = useRef(
29 (!scrollAreaRef ? window.scrollY : scrollAreaRef.current?.scrollTop) || 0
30 )
31 const [lastScrollTop, setLastScrollTop] = useState(lastScrollTopRef.current)
32 const rafRef = useRef(0)
33
34 const handleScroll = useCallback(() => {
35 if (rafRef.current) return
36 rafRef.current = requestAnimationFrame(() => {
37 rafRef.current = 0
38 const scrollTop = (!scrollAreaRef ? window.scrollY : scrollAreaRef.current?.scrollTop) || 0
39 const diff = scrollTop - lastScrollTopRef.current
40 lastScrollTopRef.current = scrollTop
41 setLastScrollTop(scrollTop)
42 if (scrollTop <= 800) {
43 setDeepBrowsing(false)
44 return
45 }
46
47 if (diff > 20) {
48 setDeepBrowsing(true)
49 } else if (diff < -20) {
50 setDeepBrowsing(false)
51 }
52 })
53 }, [scrollAreaRef])
54
55 useEffect(() => {
56 if (!active) return
57
58 const target = scrollAreaRef ? scrollAreaRef.current : window
59
60 target?.addEventListener('scroll', handleScroll)
61 return () => {
62 target?.removeEventListener('scroll', handleScroll)
63 if (rafRef.current) {
64 cancelAnimationFrame(rafRef.current)
65 rafRef.current = 0
66 }
67 }
68 }, [active, handleScroll])
69
70 return (
71 <DeepBrowsingContext.Provider value={{ deepBrowsing, lastScrollTop }}>
72 {children}
73 </DeepBrowsingContext.Provider>
74 )
75 }
76