1
- import React , { useContext , useEffect , useState } from 'react'
1
+ import React , { useContext , useEffect } from 'react'
2
2
import { GameInfo , Runner , SideloadGame } from 'common/types'
3
3
import cx from 'classnames'
4
4
import GameCard from '../GameCard'
@@ -26,62 +26,51 @@ const GamesList = ({
26
26
onlyInstalled = false ,
27
27
isRecent = false
28
28
} : Props ) : JSX . Element => {
29
- const { gameUpdates, showNonAvailable } = useContext ( ContextProvider )
29
+ const { gameUpdates } = useContext ( ContextProvider )
30
30
const { t } = useTranslation ( )
31
- const [ gameCards , setGameCards ] = useState < JSX . Element [ ] > ( [ ] )
32
31
33
32
useEffect ( ( ) => {
34
- let mounted = true
35
-
36
- const createGameCards = async ( ) => {
37
- if ( ! library . length ) {
38
- return
33
+ if ( library . length ) {
34
+ const options = {
35
+ root : document . querySelector ( '.listing' ) ,
36
+ rootMargin : '500px' ,
37
+ threshold : 0
39
38
}
40
- const resolvedLibrary = library . map ( async ( gameInfo ) => {
41
- const { app_name, is_installed, runner } = gameInfo
42
39
43
- let is_dlc = false
44
- if ( gameInfo . runner !== 'sideload' ) {
45
- is_dlc = gameInfo . install . is_dlc ?? false
46
- }
40
+ const callback : IntersectionObserverCallback = ( entries , observer ) => {
41
+ const entered : string [ ] = [ ]
42
+ entries . forEach ( ( entry ) => {
43
+ if ( entry . intersectionRatio > 0 ) {
44
+ // when a card is intersecting the viewport
45
+ const appName = ( entry . target as HTMLDivElement ) . dataset
46
+ . appName as string
47
47
48
- if ( is_dlc ) {
49
- return null
50
- }
51
- if ( ! is_installed && onlyInstalled ) {
52
- return null
53
- }
48
+ // store this appName for later
49
+ entered . push ( appName )
50
+ // stop observing this element
51
+ observer . unobserve ( entry . target )
52
+ }
53
+ } )
54
54
55
- const hasUpdate = is_installed && gameUpdates ?. includes ( app_name )
56
- return (
57
- < GameCard
58
- key = { app_name }
59
- hasUpdate = { hasUpdate }
60
- buttonClick = { ( ) => {
61
- if ( gameInfo . runner !== 'sideload' )
62
- handleGameCardClick ( app_name , runner , gameInfo )
63
- } }
64
- forceCard = { layout === 'grid' }
65
- isRecent = { isRecent }
66
- gameInfo = { gameInfo }
67
- />
55
+ // dispatch an event with the newley visible cards
56
+ // check GameCard for the other side of this detection
57
+ window . dispatchEvent (
58
+ new CustomEvent ( 'visible-cards' , { detail : { appNames : entered } } )
68
59
)
69
- } )
70
- const gameCardElements = ( await Promise . all (
71
- resolvedLibrary
72
- ) ) as JSX . Element [ ]
73
-
74
- if ( mounted ) {
75
- setGameCards ( gameCardElements )
76
60
}
77
- }
78
61
79
- createGameCards ( )
62
+ const observer = new IntersectionObserver ( callback , options )
63
+
64
+ document . querySelectorAll ( '[data-invisible]' ) . forEach ( ( card ) => {
65
+ observer . observe ( card )
66
+ } )
80
67
81
- return ( ) => {
82
- mounted = false
68
+ return ( ) => {
69
+ observer . disconnect ( )
70
+ }
83
71
}
84
- } , [ library , onlyInstalled , layout , gameUpdates , isRecent , showNonAvailable ] )
72
+ return ( ) => ( { } )
73
+ } , [ library ] )
85
74
86
75
return (
87
76
< div
@@ -100,7 +89,37 @@ const GamesList = ({
100
89
< span > { t ( 'wine.actions' , 'Action' ) } </ span >
101
90
</ div >
102
91
) }
103
- { ! ! library . length && gameCards }
92
+ { ! ! library . length &&
93
+ library . map ( ( gameInfo ) => {
94
+ const { app_name, is_installed, runner } = gameInfo
95
+
96
+ let is_dlc = false
97
+ if ( gameInfo . runner !== 'sideload' ) {
98
+ is_dlc = gameInfo . install . is_dlc ?? false
99
+ }
100
+
101
+ if ( is_dlc ) {
102
+ return null
103
+ }
104
+ if ( ! is_installed && onlyInstalled ) {
105
+ return null
106
+ }
107
+
108
+ const hasUpdate = is_installed && gameUpdates ?. includes ( app_name )
109
+ return (
110
+ < GameCard
111
+ key = { app_name }
112
+ hasUpdate = { hasUpdate }
113
+ buttonClick = { ( ) => {
114
+ if ( gameInfo . runner !== 'sideload' )
115
+ handleGameCardClick ( app_name , runner , gameInfo )
116
+ } }
117
+ forceCard = { layout === 'grid' }
118
+ isRecent = { isRecent }
119
+ gameInfo = { gameInfo }
120
+ />
121
+ )
122
+ } ) }
104
123
</ div >
105
124
)
106
125
}
0 commit comments