@@ -8,6 +8,7 @@ const baseClass = 'thumbnail'
8
8
import type { SanitizedCollectionConfig } from 'payload'
9
9
10
10
import { File } from '../../graphics/File/index.js'
11
+ import { useIntersect } from '../../hooks/useIntersect.js'
11
12
import { ShimmerEffect } from '../ShimmerEffect/index.js'
12
13
13
14
export type ThumbnailProps = {
@@ -29,12 +30,20 @@ export const Thumbnail = (props: ThumbnailProps) => {
29
30
const [ src , setSrc ] = React . useState < null | string > (
30
31
fileSrc ? `${ fileSrc } ${ imageCacheTag ? `?${ imageCacheTag } ` : '' } ` : null ,
31
32
)
33
+ const [ intersectionRef , entry ] = useIntersect ( )
34
+ const [ hasPreloaded , setHasPreloaded ] = React . useState ( false )
35
+
32
36
React . useEffect ( ( ) => {
33
37
if ( ! fileSrc ) {
34
38
setFileExists ( false )
35
39
return
36
40
}
37
41
42
+ if ( ! entry ?. isIntersecting || hasPreloaded ) {
43
+ return
44
+ }
45
+ setHasPreloaded ( true )
46
+
38
47
if ( fileType === 'video' ) {
39
48
const video = document . createElement ( 'video' )
40
49
video . src = fileSrc
@@ -58,12 +67,12 @@ export const Thumbnail = (props: ThumbnailProps) => {
58
67
img . src = fileSrc
59
68
img . onload = ( ) => setFileExists ( true )
60
69
img . onerror = ( ) => setFileExists ( false )
61
- } , [ fileSrc , fileType , imageCacheTag ] )
70
+ } , [ fileSrc , fileType , imageCacheTag , entry , hasPreloaded ] )
62
71
63
72
const alt = props . alt || ( filename as string )
64
73
65
74
return (
66
- < div className = { classNames } >
75
+ < div className = { classNames } ref = { intersectionRef } >
67
76
{ fileExists === undefined && < ShimmerEffect height = "100%" /> }
68
77
{ fileExists && < img alt = { alt } src = { src } /> }
69
78
{ fileExists === false && < File /> }
0 commit comments