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)