@@ -2,6 +2,9 @@ import { clsx } from 'clsx'
22import * as React from 'react'
33
44const isServer = typeof document === 'undefined'
5+ const useIsomorphicLayoutEffect = isServer
6+ ? React . useEffect
7+ : React . useLayoutEffect
58
69function BlurrableImage ( {
710 img,
@@ -12,37 +15,40 @@ function BlurrableImage({
1215 blurDataUrl ?: string
1316} & React . HTMLAttributes < HTMLDivElement > ) {
1417 const id = React . useId ( )
15- const [ visible , setVisible ] = React . useState ( ( ) => {
16- if ( isServer ) return false
17-
18- // on the client, it's possible the images has already finished loading.
19- // we've got the data-evt-onload attribute on the image
20- // (which our entry.server replaces with simply "onload") which will remove
21- // the class "opacity-0" from the image once it's loaded. So we'll check
22- // if the image is already loaded and if so, we know that visible should
23- // initialize to true.
24- const el = document . getElementById ( id )
25- return el instanceof HTMLImageElement && ! el . classList . contains ( 'opacity-0' )
26- } )
18+ const [ visible , setVisible ] = React . useState ( false )
2719 const jsImgElRef = React . useRef < HTMLImageElement > ( null )
2820
21+ useIsomorphicLayoutEffect ( ( ) => {
22+ const imageEl = jsImgElRef . current
23+ if ( ! imageEl ) return
24+
25+ // On the client, the image might have already loaded before hydration,
26+ // which removes the opacity class via the server-rendered onload handler.
27+ if ( imageEl . complete || ! imageEl . classList . contains ( 'opacity-0' ) ) {
28+ setVisible ( true )
29+ }
30+ } , [ ] )
31+
2932 React . useEffect ( ( ) => {
30- if ( ! jsImgElRef . current ) return
31- if ( jsImgElRef . current . complete ) {
33+ const imageEl = jsImgElRef . current
34+ if ( ! imageEl ) return
35+ if ( imageEl . complete ) {
3236 setVisible ( true )
3337 return
3438 }
3539
3640 let current = true
37- jsImgElRef . current . addEventListener ( 'load' , ( ) => {
41+ const handleLoad = ( ) => {
3842 if ( ! jsImgElRef . current || ! current ) return
3943 setTimeout ( ( ) => {
4044 setVisible ( true )
4145 } , 0 )
42- } )
46+ }
47+ imageEl . addEventListener ( 'load' , handleLoad )
4348
4449 return ( ) => {
4550 current = false
51+ imageEl . removeEventListener ( 'load' , handleLoad )
4652 }
4753 } , [ ] )
4854
0 commit comments