1
- import { useEffect , useState } from 'react' ;
1
+ import { useEffect , useMemo , useState } from 'react' ;
2
2
3
3
import usePrevious from '@/components/react/hooks/usePrevious' ;
4
4
import { cn } from '@/utils/styles' ;
@@ -23,21 +23,31 @@ const ImageBlurPreloader: FC<Props> = ({
23
23
className,
24
24
divClassName,
25
25
} ) => {
26
- const [ hasLoaded , setHasLoaded ] = useState ( false ) ;
26
+ const [ isLoadingMain , setIsLoadingMain ] = useState ( true ) ;
27
+ const [ isLoadingBlur , setIsLoadingBlur ] = useState ( true ) ;
28
+
27
29
const prevMainAttributes = usePrevious ( mainAttributes ) ;
28
30
29
- // reset hasLoaded on main image change
31
+ const { src, srcSet } = mainAttributes ;
32
+ const { src : prevSrc , srcSet : prevSrcSet } = prevMainAttributes ?? { } ;
33
+
34
+ const isNewImage = useMemo (
35
+ ( ) => ! ( prevSrc === src && prevSrcSet === srcSet ) ,
36
+ [ src , srcSet , prevSrc , prevSrcSet ]
37
+ ) ;
38
+
39
+ // reset isLoading on main image change
30
40
useEffect ( ( ) => {
31
- // store var in useMemo
32
- if ( prevMainAttributes !== mainAttributes ) {
33
- setHasLoaded ( false ) ;
41
+ if ( isNewImage ) {
42
+ setIsLoadingBlur ( true ) ;
43
+ setIsLoadingMain ( true ) ;
34
44
}
35
- } , [ prevMainAttributes , mainAttributes , setHasLoaded ] ) ;
45
+ } , [ isNewImage , setIsLoadingMain , setIsLoadingBlur ] ) ;
36
46
37
47
// important: main image must be in DOM for onLoad to work
38
48
// unmount and display: none will fail
39
- const handleLoad = ( ) => {
40
- setHasLoaded ( true ) ; // check if new image
49
+ const handleLoadMain = ( ) => {
50
+ setIsLoadingMain ( false ) ;
41
51
onMainLoaded ?.( ) ;
42
52
} ;
43
53
@@ -47,7 +57,7 @@ const ImageBlurPreloader: FC<Props> = ({
47
57
height : mainAttributes . height ,
48
58
} ;
49
59
50
- const hasImage = hasLoaded
60
+ const hasImage = isLoadingMain
51
61
? mainAttributes . src || mainAttributes . srcSet
52
62
: blurAttributes . src || blurAttributes . srcSet ;
53
63
@@ -59,17 +69,19 @@ const ImageBlurPreloader: FC<Props> = ({
59
69
< img
60
70
{ ...blurAttributes }
61
71
{ ...commonAttributes }
72
+ onLoad = { ( ) => setIsLoadingBlur ( false ) }
62
73
className = { cn ( 'object-cover absolute top-0 left-0 size-full' , className ) }
63
74
/>
64
75
65
76
{ /* main image */ }
66
77
< img
67
78
{ ...mainAttributes }
68
79
{ ...commonAttributes }
69
- onLoad = { handleLoad }
80
+ onLoad = { handleLoadMain }
70
81
className = { cn (
71
82
'object-cover absolute top-0 left-0 size-full' ,
72
- hasLoaded ? 'opacity-100' : 'opacity-0' ,
83
+ // important: dont hide main image until next blur image is loaded
84
+ isLoadingMain && ! isLoadingBlur ? 'opacity-0' : 'opacity-100' ,
73
85
className
74
86
) }
75
87
/>
0 commit comments