@@ -17,15 +17,26 @@ const isBrowser =
1717 typeof window . document !== "undefined" &&
1818 typeof window . document . createElement !== "undefined" ;
1919
20+ const event = "hydrate" ;
21+
22+ const io =
23+ isBrowser && IntersectionObserver
24+ ? new IntersectionObserver ( entries => {
25+ entries . forEach ( entry => {
26+ if ( entry . isIntersecting || entry . intersectionRatio > 0 ) {
27+ entry . target . dispatchEvent ( new CustomEvent ( event ) ) ;
28+ }
29+ } ) ;
30+ } )
31+ : null ;
32+
2033// React currently throws a warning when using useLayoutEffect on the server.
2134const useIsomorphicLayoutEffect = isBrowser
2235 ? React . useLayoutEffect
2336 : React . useEffect ;
2437
2538const LazyHydrate : React . FunctionComponent < Props > = function ( props ) {
2639 const childRef = React . useRef < HTMLDivElement > ( null ) ;
27- const cleanupFns = React . useRef < VoidFunction [ ] > ( [ ] ) ;
28- const io = React . useRef < IntersectionObserver > ( null ) ;
2940
3041 // Always render on server
3142 const [ hydrated , setHydrated ] = React . useState ( ! isBrowser ) ;
@@ -47,16 +58,17 @@ const LazyHydrate: React.FunctionComponent<Props> = function(props) {
4758
4859 useIsomorphicLayoutEffect ( ( ) => {
4960 // No SSR Content
50- if ( childRef . current . childElementCount === 0 ) {
61+ if ( ! childRef . current . hasChildNodes ( ) ) {
5162 setHydrated ( true ) ;
5263 }
5364 } , [ ] ) ;
5465
5566 React . useEffect ( ( ) => {
5667 if ( ssrOnly || hydrated ) return ;
68+ const cleanupFns : VoidFunction [ ] = [ ] ;
5769 function cleanup ( ) {
58- while ( cleanupFns . current . length ) {
59- cleanupFns . current . pop ( ) ( ) ;
70+ while ( cleanupFns . length ) {
71+ cleanupFns . pop ( ) ( ) ;
6072 }
6173 }
6274 function hydrate ( ) {
@@ -67,52 +79,43 @@ const LazyHydrate: React.FunctionComponent<Props> = function(props) {
6779 // @ts -ignore
6880 if ( requestIdleCallback ) {
6981 // @ts -ignore
70- const idleCallbackId = requestIdleCallback (
71- ( ) => requestAnimationFrame ( ( ) => hydrate ( ) ) ,
72- { timeout : 500 }
73- ) ;
74- cleanupFns . current . push ( ( ) => {
82+ const idleCallbackId = requestIdleCallback ( hydrate , { timeout : 500 } ) ;
83+ cleanupFns . push ( ( ) => {
7584 // @ts -ignore
7685 cancelIdleCallback ( idleCallbackId ) ;
7786 } ) ;
7887 } else {
79- setTimeout ( hydrate , 2000 ) ;
88+ const id = setTimeout ( hydrate , 2000 ) ;
89+ cleanupFns . push ( ( ) => {
90+ clearTimeout ( id ) ;
91+ } ) ;
8092 }
8193 }
8294
95+ let events = Array . isArray ( on ) ? on . slice ( ) : [ on ] ;
96+
8397 if ( whenVisible ) {
84- if ( io . current === null && IntersectionObserver ) {
85- io . current = new IntersectionObserver ( entries => {
86- entries . forEach ( entry => {
87- if (
88- entry . target . parentElement === childRef . current &&
89- ( entry . isIntersecting || entry . intersectionRatio > 0 )
90- ) {
91- hydrate ( ) ;
92- }
93- } ) ;
94- } ) ;
95- }
96- if ( io . current && childRef . current . childElementCount !== 0 ) {
98+ if ( io && childRef . current . childElementCount ) {
9799 // As root node does not have any box model, it cannot intersect.
98- io . current . observe ( childRef . current . children [ 0 ] ) ;
99- cleanupFns . current . push ( ( ) => {
100- io . current . unobserve ( childRef . current . children [ 0 ] ) ;
100+ const el = childRef . current . children [ 0 ] ;
101+ io . observe ( el ) ;
102+ events . push ( event as keyof HTMLElementEventMap ) ;
103+
104+ cleanupFns . push ( ( ) => {
105+ io . unobserve ( el ) ;
101106 } ) ;
102107 } else {
103108 return hydrate ( ) ;
104109 }
105110 }
106111
107- const events = Array . isArray ( on ) ? on : [ on ] ;
108-
109112 events . forEach ( event => {
110113 childRef . current . addEventListener ( event , hydrate , {
111114 once : true ,
112115 capture : true ,
113116 passive : true
114117 } ) ;
115- cleanupFns . current . push ( ( ) => {
118+ cleanupFns . push ( ( ) => {
116119 childRef . current . removeEventListener ( event , hydrate , { capture : true } ) ;
117120 } ) ;
118121 } ) ;
0 commit comments