@@ -2,9 +2,6 @@ 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
85
96function BlurrableImage ( {
107 img,
@@ -15,40 +12,41 @@ function BlurrableImage({
1512 blurDataUrl ?: string
1613} & React . HTMLAttributes < HTMLDivElement > ) {
1714 const id = React . useId ( )
18- const [ visible , setVisible ] = React . useState ( false )
19- const jsImgElRef = React . useRef < HTMLImageElement > ( null )
15+ const [ visible , setVisible ] = React . useState ( ( ) => {
16+ if ( isServer ) return false
2017
21- useIsomorphicLayoutEffect ( ( ) => {
22- const imageEl = jsImgElRef . current
23- if ( ! imageEl ) return
18+ // During hydration the element might not be in the DOM yet, so guard
19+ // against null to avoid crashing and fall back to the blurred state.
20+ const el = document . getElementById ( id )
21+ if ( ! ( el instanceof HTMLImageElement ) ) return false
2422
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- } , [ ] )
23+ // on the client, it's possible the images has already finished loading.
24+ // we've got the data-evt-onload attribute on the image
25+ // (which our entry.server replaces with simply "onload") which will remove
26+ // the class "opacity-0" from the image once it's loaded. So we'll check
27+ // if the image is already loaded and if so, we know that visible should
28+ // initialize to true.
29+ return ! el . classList . contains ( 'opacity-0' )
30+ } )
31+ const jsImgElRef = React . useRef < HTMLImageElement > ( null )
3132
3233 React . useEffect ( ( ) => {
33- const imageEl = jsImgElRef . current
34- if ( ! imageEl ) return
35- if ( imageEl . complete ) {
34+ if ( ! jsImgElRef . current ) return
35+ if ( jsImgElRef . current . complete ) {
3636 setVisible ( true )
3737 return
3838 }
3939
4040 let current = true
41- const handleLoad = ( ) => {
41+ jsImgElRef . current . addEventListener ( 'load' , ( ) => {
4242 if ( ! jsImgElRef . current || ! current ) return
4343 setTimeout ( ( ) => {
4444 setVisible ( true )
4545 } , 0 )
46- }
47- imageEl . addEventListener ( 'load' , handleLoad )
46+ } )
4847
4948 return ( ) => {
5049 current = false
51- imageEl . removeEventListener ( 'load' , handleLoad )
5250 }
5351 } , [ ] )
5452
0 commit comments