1
1
import React , {
2
2
useState ,
3
3
useMemo ,
4
- useEffect ,
5
- useLayoutEffect ,
6
- useRef ,
7
- useCallback ,
8
- ReactNode ,
9
- createContext ,
10
- } from 'react'
4
+ useEffect , useRef , ReactNode
5
+ } from 'react' ;
11
6
12
- export function VirtualList (
13
- props ,
7
+ export type Props < ITEM > = {
8
+ itemSize ?: number ,
9
+ buffer ?: number ,
10
+ items : ITEM [ ] ,
11
+ renderItem : ( item : ITEM , index : number ) => ReactNode
12
+ } & typeof defaultProps
13
+
14
+ export const defaultProps = {
15
+ listSize : 1000 ,
16
+ }
17
+ export function VirtualList < ITEM > (
18
+ props : Props < ITEM > & React . HTMLProps < HTMLElement > ,
14
19
) {
15
20
const [ itemSize , setitemSize ] = useState ( props . itemSize || 100 ) ;
16
21
const buffer = useMemo ( ( ) => props . buffer || Math . max ( itemSize * 5 , 100 ) , [ props . buffer , itemSize ] ) ;
17
22
const count = props . items . length
18
- const list = useRef ( null ) ;
19
- const listInner = useRef ( null ) ;
23
+ const list = useRef < HTMLDivElement > ( null ) ;
24
+ const listInner = useRef < HTMLDivElement > ( null ) ;
20
25
const prevScrollTop = useRef ( 0 ) ;
21
26
const [ scrollTop , setscrollTop ] = useState ( 0 ) ;
22
- const [ listSize , setlistSize ] = useState ( props . listSize || 1000 ) ;
27
+ const [ listSize , setlistSize ] = useState ( props . listSize ) ;
28
+
23
29
//
24
30
const totalSpace = itemSize * count
25
31
let topSpace = scrollTop - buffer
26
32
let bottomSpace = totalSpace - scrollTop - listSize - buffer
27
- let startIndex , endIndex
33
+ let startIndex = 0 , endIndex = 0
28
34
29
35
if ( topSpace <= 0 ) {
30
36
topSpace = 0
@@ -41,7 +47,7 @@ export function VirtualList(
41
47
bottomSpace = 0
42
48
}
43
49
const visible = props . items . slice ( startIndex , endIndex )
44
- const listInnerStyle = { paddingTop : `${ topSpace } px` , boxSizing : 'border-box' }
50
+ const listInnerStyle : any = { paddingTop : `${ topSpace } px` , boxSizing : 'border-box' }
45
51
if ( bottomSpace < itemSize * 5 ) {
46
52
listInnerStyle [ 'paddingBottom' ] = `${ bottomSpace } px`
47
53
} else {
@@ -53,9 +59,9 @@ export function VirtualList(
53
59
// get avg item size
54
60
let count = 0
55
61
let totalHeight = 0
56
- for ( const el of listInner . current . children ) {
62
+ for ( const el of listInner . current ! . children ) {
57
63
const style = getComputedStyle ( el )
58
- totalHeight += el . offsetHeight + parseFloat ( style . marginTop ) + parseFloat ( style . marginBottom )
64
+ totalHeight += ( el as HTMLElement ) . offsetHeight + parseFloat ( style . marginTop ) + parseFloat ( style . marginBottom )
59
65
count ++
60
66
}
61
67
setitemSize ( totalHeight / count )
@@ -76,4 +82,6 @@ export function VirtualList(
76
82
{ visible . map ( ( item , i ) => props . renderItem ( item , i + startIndex ) ) }
77
83
</ div >
78
84
</ div >
79
- }
85
+ }
86
+
87
+ VirtualList . defaultProps = defaultProps
0 commit comments