DEV Community

Cover image for Import on Interaction
Jayant
Jayant

Posted on

Import on Interaction

WHAT

It is a performance pattern, that allows us on import things over network, on some interaction.
This can be done using React.lazy , Suspense, Dynamic Import & facade pattern.

Instead of Eager Loading (Loading resources immediately, on page load) , we load them on interaction.

Facade pattern : It is a design pattern that provides a simplified interface to a more complex subsystem. Means we mimic the UI of the deferred resource using HTML/CSS/JS.

Examples :

  • Showing 3rd Party Widgets : We load the 3rd party widget on interaction, initially we show a facade.
    • Video Embeds
    • Chat Widgets
    • Social Media Widgets
  • Non-critical resources
    • EmojiPicker: that didn't used that much.
    • Filters
  • Authentication SDK's : Our app supports 3rd party authentication, so loading that on initial render will be a bad idea. Instead import it on interaction - Basically on button click or show a facade to the user.

  • Infrequently used features

    • Scroll to Top : Load animation libraries (e.g., react-scroll) only when the user clicks a "Back to Top" button.
    const ScrollToTop = ()=>{ const [scrollLibrary,setScrollLibrary] = useState(null); const handleScroll = ()=>{ import('react-scroll').then((module)=>{ setScrollLibrary(module); module.animateScroll.scrollToTop(); }) } return <> <button onClick={handleScroll}>Back to Top</button>  </> } 
    • Export : Defer loading libraries for generating PDFs or CSVs (e.g., jsPDF) until the user clicks an export button.
    • Analytics : Don't preload/prefecth this as that many users don't use it.
    • Tabbed Interface : Load the tab component only when the user clicks a tab.
     const Tab1 = React.lazy(()=>import('./Tab1)); const Tab2 = React.lazy(()=>import('./Tab2)); const tabbedInterface = ()=>{ const [activeTab,setActiveTab] = useState(0); return <> <button onClick={()=>setActiveTab(0)}>Tab 1</button>  <button onClick={()=>setActiveTab(1)}>Tab 2</button>  <Suspense fallback={<div>Loading...</div>}> // In Server side use Loadable Component {activeTab === 0 && <Tab1 />} {activeTab === 1 && <Tab2 />} </Suspense>  </>; } 

HOW

Facade for a Youtube Video Embed

const YoutubeFacade = ()=>{ const [isEmbedLoaded,setIsEmbedLoaded] = useState(false); return <div classname='youtube-embed'> { !isEmbedLoaded ? <> <img src={`https://img.youtube.com/vi/${videoId}/hqdefault.jpg`} alt="Video thumbnail" style={{ width: '100%', height: '100%' }} />  <button style={{ position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%, -50%)', padding: '10px 20px', background: 'red', color: 'white', border: 'none', }} > Play </button>  </div>  </>:<>  <iframe width="560" height="315" src={`https://www.youtube.com/embed/${videoId}?autoplay=1`} frameBorder="0" allow="autoplay; encrypted-media" allowFullScreen /> </>  } </div> } 
Enter fullscreen mode Exit fullscreen mode

Only after the user clicks the facade does the element get added to the DOM with the.

Don't use this when

  • you need to do autoplay
  • you need that for SEO

Facade for a Login with Google

const GoogleLoginFacade = ()=>{ const [isSdkLoaded,setIsSdkLoaded] = useState(false); const loadGoogleSDK = ()=>{ import("./google-auth").then((module)=>{ // a new bundle is fetched with some autogenerated name, if you want a more friendly then you define its name by doing this - import(/*webpackChunkName:"google-sdk"*/ './google-auth') module.initGoogleSignIn(); setIsSdkLoaded(true); }) } return <> { !isSdkLoaded ? <> <div className='google-login-button'> <button onClick={loadGoogleSDK}>Login with Google</button>  </div>  </>:<>  <div id="google-signin-button" /> </>  } </> } // This get loaded on demand // google-auth.js export const initGoogleSignIn = () => { const script = document.createElement('script'); script.src = 'https://apis.google.com/js/client:platform.js?onload=showLoginScreen'; script.async = true; document.body.appendChild(script); }; 
Enter fullscreen mode Exit fullscreen mode

Top comments (0)