-
-
Save sergeydt/4b8c7bc3637098c745ccf8cad2144f25 to your computer and use it in GitHub Desktop.
Example of React hooks for Lazy Loading modules and components (Next.js)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Usage example: | |
// function MyComponent() { | |
// const swiperReferenceEl = useRef(); | |
// const swiperReference = useRef(); | |
// const swiperModule = useReached(swiperReferenceEl, async () => { | |
// const [ swiperJS ] = await Promise.all([import('swiper/bundle'), import('swiper/swiper-bundle.css')]); | |
// return swiperJS; | |
// }) | |
// process.browser && useLayoutEffect(() => { | |
// if (!swiperModule.isInit || swiperReference.current) { | |
// return undefined; | |
// } | |
// swiperReference.current = new swiperModule.Swiper(swiperReferenceEl.current, { | |
// // ... | |
// }); | |
// // ... | |
// }, [swiperModule]); | |
// } | |
import throttle from 'lodash/throttle' | |
import { useEffect, useState } from 'react'; | |
import { isElementInViewport } from 'lib/helpers/styles'; | |
const mockImport = () => Promise.resolve({}); | |
export default function useReached( | |
ref, | |
moduleImport = mockImport, | |
delay = 7000, | |
) { | |
const [module, setModule] = useState({isInit: false}); | |
process.browser && useEffect(() => { | |
if (module.isInit) { | |
return undefined; | |
} | |
_tryInit(false); | |
setTimeout(_tryInit, 1000); | |
const t = setInterval(() => { | |
_tryInit(true); | |
}, delay); | |
async function _tryInit(force = false) { | |
if (module.isInit || !ref?.current) { | |
return null; | |
} | |
if (force || isElementInViewport(ref.current)) { | |
clearInterval(t); | |
const m = await moduleImport(); | |
setModule({ ...m, isInit: true }); | |
} | |
} | |
const onScroll = throttle(_tryInit, 300, { leading: false }); | |
window.addEventListener('scroll', onScroll); | |
return () => { | |
window.removeEventListener('scroll', onScroll); | |
} | |
}, [delay, module, moduleImport, ref]); | |
return module; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Usage example: | |
// const LazyYoutubePlayer = withLazyReached({ | |
// importCb: () => import('components/youtube-player'), | |
// }); | |
import { useRef, forwardRef, memo } from 'react'; | |
import dynamic from 'next/dynamic'; | |
import useReached from 'lib/hooks/use-reached'; | |
const mockImport = () => Promise.resolve({}); | |
export default function withLazyReached({ importCb, delay = 7000, options = {} }) { | |
const Component = dynamic(importCb, options); | |
const fr = forwardRef((props, fRef) => { | |
const ref = useRef(); | |
const reached = useReached(ref, mockImport, delay); | |
if (reached.isInit) { | |
return <Component {...props} ref={fRef} forwardedRef={fRef}/>; | |
} else { | |
return <div ref={ref}/>; | |
} | |
}); | |
return memo(fr); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment