1
1
import { any , arrayOf , element , func , node , oneOfType } from 'prop-types' ;
2
- import React , { createRef , useEffect , useLayoutEffect , useState , Ref } from 'react' ;
3
- import convertListToArray from '../___utils/convertListToArray' ;
2
+ import React , { createRef , Ref , useEffect , useLayoutEffect , useState } from 'react' ;
4
3
import { handleRenderGroupSeparator , handleRenderItem , renderFunc } from './uiFunctions' ;
5
4
6
5
interface Props {
@@ -11,82 +10,84 @@ interface Props {
11
10
12
11
const ScrollRenderer = ( props : Props ) => {
13
12
const { list, renderItem, groupSeparator} = props ;
14
- const [ render , setRender ] = useState ( { renderList : [ ] , index : 0 , prevScrollPosition : 0 } ) ;
13
+ const [ render , setRender ] = useState ( { renderList : [ ] , index : 0 } ) ;
15
14
const [ mounted , setMounted ] = useState ( false ) ;
16
- const dataList = convertListToArray ( list ) ;
15
+ const [ setupCount , setSetupCount ] = useState ( - 1 ) ;
17
16
const containerRef : Ref < HTMLElement > = createRef ( ) ;
18
- let adding = false ;
19
17
20
18
const renderThisItem = handleRenderItem ( renderItem , handleRenderGroupSeparator ( groupSeparator ) ) ;
21
19
22
- const addItem = ( container : any , prevScrollPosition = render . prevScrollPosition ) => {
23
- if ( ! adding && render . index < dataList . length ) {
24
- adding = true ;
25
- // @ts -ignore
26
- const count = getComputedStyle ( container as HTMLElement ) . display === 'grid' ? 10 : 5 ;
20
+ const updateRenderInfo = ( count = 10 ) => {
21
+ if ( render . index < list . length ) {
22
+ const index = render . index + count ;
27
23
setRender ( {
28
- prevScrollPosition,
29
- renderList : [ ...render . renderList , ...dataList . slice ( render . index , render . index + count ) ] as any ,
30
- index : render . index + count
24
+ renderList : list . slice ( 0 , index ) as any ,
25
+ index
31
26
} ) ;
32
27
}
33
28
} ;
34
29
35
30
const onScroll = ( span : any ) => ( ) => {
36
- const startingPoint = span . parentNode . offsetTop + span . parentNode . offsetHeight ;
37
- const anchorPos = span . offsetTop - span . parentNode . scrollTop ;
31
+ requestAnimationFrame ( ( ) => {
32
+ const startingPoint = span . parentNode . offsetTop + span . parentNode . offsetHeight ;
33
+ const anchorPos = span . offsetTop - span . parentNode . scrollTop ;
38
34
39
- if ( anchorPos <= ( startingPoint + ( span . parentNode . offsetHeight * 2 ) ) ) {
40
- requestAnimationFrame ( ( ) => addItem ( span . parentNode , span . parentNode . scrollTop ) ) ;
41
- }
35
+ if ( anchorPos <= ( startingPoint + ( span . parentNode . offsetHeight * 2 ) ) ) {
36
+ updateRenderInfo ( ) ;
37
+ }
38
+ } ) ;
42
39
} ;
43
40
44
- useEffect ( ( ) => {
45
- if ( mounted ) { // reset list on list change
46
- setRender ( {
47
- renderList : [ ] ,
48
- index : 0 ,
49
- prevScrollPosition : 0
50
- } ) ;
51
- }
52
- } , [ list ] ) ;
53
-
54
41
useEffect ( ( ) => { // when mounted
55
42
setMounted ( true ) ;
56
43
57
44
return ( ) => { // when unmounted
58
- if ( containerRef . current ) {
59
- ( containerRef as any ) . current . parentNode . removeEventListener ( 'scroll' , onScroll , true ) ;
60
- }
45
+ setMounted ( false ) ;
61
46
} ;
62
47
} , [ ] ) ;
63
48
49
+ useLayoutEffect ( ( ) => {
50
+ if ( mounted ) { // reset list on list change
51
+ const span : any = containerRef . current ;
52
+ const pos = span . parentNode . scrollTop ;
53
+ const index = Math . max ( render . renderList . length , setupCount ) ;
54
+
55
+ setRender ( {
56
+ renderList : list . slice ( 0 , index ) as any ,
57
+ index
58
+ } ) ;
59
+
60
+ requestAnimationFrame ( ( ) => {
61
+ span . parentNode . scrollTop = pos ;
62
+ } ) ;
63
+ }
64
+ } , [ list ] ) ;
65
+
64
66
useLayoutEffect ( ( ) => {
65
67
const span : any = containerRef . current ;
66
- let container : any = null ;
67
68
const handleScroll = onScroll ( span ) ;
69
+ let container : any = null ;
70
+
68
71
if ( span ) {
69
72
container = span . parentNode ;
70
- // populate double the container height of items
71
- if ( render . index === 0 || container . scrollHeight <= ( container . offsetHeight * 2 ) ) {
72
- requestAnimationFrame ( ( ) => addItem ( container ) ) ;
73
- }
74
-
75
- if ( render . index > 0 && dataList . length === render . renderList . length ) {
76
- container . removeEventListener ( 'scroll' , handleScroll , true ) ;
77
- } else {
78
- container . addEventListener ( 'scroll' , handleScroll , true ) ;
79
- }
73
+ requestAnimationFrame ( ( ) => {
74
+ // populate double the container height of items
75
+ if ( render . index === 0 || container . scrollHeight <= ( container . offsetHeight * 2 ) ) {
76
+ updateRenderInfo ( ) ;
77
+ } else if ( setupCount === - 1 ) {
78
+ setSetupCount ( render . index ) ;
79
+ }
80
+ } ) ;
80
81
81
- adding = false ;
82
+ container . addEventListener ( 'scroll' , handleScroll , { passive : true } ) ;
82
83
}
83
84
84
85
return ( ) => { // when unmounted
85
86
if ( span ) {
86
- container . removeEventListener ( 'scroll' , handleScroll , true ) ;
87
+ container . removeEventListener ( 'scroll' , handleScroll , { passive : true } ) ;
87
88
}
88
89
} ;
89
- } , [ render . index ] ) ;
90
+ } , [ render . index , list . length ] ) ;
90
91
91
92
return (
92
93
< >
0 commit comments