1
- import React , {
1
+ import {
2
2
ReactNode ,
3
3
createRef ,
4
4
useEffect ,
5
5
useMemo ,
6
6
useState ,
7
- RefObject ,
8
7
useCallback ,
9
8
} from 'react' ;
10
9
import { debounce } from './utils' ;
11
- import { Provider } from './context' ;
10
+ import { Provider , Section } from './context' ;
12
11
import smoothscroll from 'smoothscroll-polyfill' ;
13
12
14
13
type Props = {
@@ -18,12 +17,6 @@ type Props = {
18
17
children : ReactNode ;
19
18
} ;
20
19
21
- type Section = {
22
- id : string ;
23
- ref : RefObject < HTMLElement > ;
24
- meta : unknown ;
25
- } ;
26
-
27
20
if ( typeof window !== 'undefined' ) {
28
21
smoothscroll . polyfill ( ) ;
29
22
}
@@ -35,7 +28,7 @@ export const ScrollingProvider = ({
35
28
children,
36
29
} : Props ) => {
37
30
const [ selected , setSelected ] = useState ( '' ) ;
38
- const [ sections , setSections ] = useState < Section [ ] > ( [ ] ) ;
31
+ const [ sections , setSections ] = useState < Record < string , Section > > ( { } ) ;
39
32
40
33
useEffect ( ( ) => {
41
34
document . addEventListener ( 'scroll' , debounceScroll , true ) ;
@@ -46,12 +39,12 @@ export const ScrollingProvider = ({
46
39
} , [ sections ] ) ;
47
40
48
41
const handleScroll = useCallback ( ( ) => {
49
- const selectedSection = sections . reduce (
50
- ( acc , curr ) => {
51
- const sectionRef = curr . ref . current ;
42
+ const selectedSection = Object . keys ( sections ) . reduce (
43
+ ( acc , id ) => {
44
+ const sectionRef = sections [ id ] . ref . current ;
52
45
if ( ! sectionRef ) {
53
46
return {
54
- id : curr . id ,
47
+ id,
55
48
differenceFromTop : 0 ,
56
49
} ;
57
50
}
@@ -62,13 +55,13 @@ export const ScrollingProvider = ({
62
55
if ( differenceFromTop >= acc . differenceFromTop ) return acc ;
63
56
64
57
return {
58
+ id,
65
59
differenceFromTop,
66
- id : curr . id ,
67
60
} ;
68
61
} ,
69
62
{
70
- differenceFromTop : 9999 ,
71
63
id : '' ,
64
+ differenceFromTop : 9999 ,
72
65
} ,
73
66
) ;
74
67
@@ -77,19 +70,19 @@ export const ScrollingProvider = ({
77
70
78
71
const debounceScroll = debounce ( handleScroll , debounceDelay ) ;
79
72
80
- const registerRef = ( { id, meta } : Omit < Section , 'ref' > ) => {
73
+ const registerRef = ( { id, meta } : { id : string ; meta : unknown } ) => {
81
74
const ref = createRef < HTMLElement > ( ) ;
82
- setSections ( ( prev ) => [ ...prev , { id , ref, meta } ] ) ;
75
+ setSections ( ( prev ) => ( { ...prev , [ id ] : { ref, meta } } ) ) ;
83
76
return ref ;
84
77
} ;
85
78
86
79
const unregisterRef = ( id : string ) => {
87
- setSections ( ( prev ) => prev . filter ( ( section ) => section . id !== id ) ) ;
80
+ setSections ( ( { [ id ] : toRemove , ... rest } ) => rest ) ;
88
81
} ;
89
82
90
83
const scrollTo = useCallback (
91
84
( id : string ) => {
92
- const section = sections . find ( ( section ) => section . id === id ) ;
85
+ const section = sections [ id ] ;
93
86
if ( ! section ) return console . warn ( 'Section ID not recognized!' ) ; // eslint-disable-line
94
87
95
88
setSelected ( id ) ;
0 commit comments