Upgrade to Pro — share decks privately, control downloads, hide ads and more …

React.lazy() and You: A Code Splitting Primer

React.lazy() and You: A Code Splitting Primer

In this talk we'll go over code splitting with React.lazy() and React.Suspense and some of the appropriate places to implement it as well as some of the pitfalls of this approach.

NOTE: This talk was given as part of the Charlotte Front End Developers Meetup: https://www.meetup.com/Charlotte-Front-End-Developers/events/259279159/

Eric Allen

March 14, 2019
Tweet

More Decks by Eric Allen

Other Decks in Technology

Transcript

  1. Agenda Agenda What is it? When to use it? When

    not to use it? Usage examples. Q&A 2 . 2
  2. What is React.lazy()? What is React.lazy()? introduced in 16.6.0 simple

    wrapper for dynamic imports abstracts away boilerplate used with React.Suspense Component to provide fallback 3 . 1
  3. What are dynamic imports? What are dynamic imports? Stage 3

    (Candidate) in TC39 Process functional import for JavaScript Modules returns a Promise that resolves to JavaScript Module facilitates developer-defined code splitting in build tools like webpack 3 . 2
  4. What is code splitting? What is code splitting? built into

    webpack breaking JS bundle into into smaller "chunks" allows for smaller, more focused bundles can be used to load code on demand, in parallel, based on priority, etc. 3 . 3
  5. What's the point? What's the point? Lazy load expensive components

    Only deliver the necessary code to the browser Code splitting can provide novel approaches to code organization and architecture 4 . 1
  6. But why? But why? Average website is ~2MB [1] After

    images (and video), JavaScript is the biggest contributor to that bloat ~40% of users abandon a website that takes longer than 3 seconds to load [2] [1] [2] https://httparchive.org/reports/page-weight?start=2018_01_01&end=latest&view=list https://neilpatel.com/blog/loading-time/ 4 . 2
  7. "Expensive" Components "Expensive" Components Data Viz w/ heavy library like

    d3 Components that users rarely interact with Components that are "below the fold" 4 . 3
  8. Anything not in the Anything not in the Critical Path

    Critical Path could could be expensive. be expensive. 4 . 4
  9. Unnecessary Code Unnecessary Code Code behind a feature flag A/B

    tests that the user isn't experiencing Routes the user will likely never visit 4 . 5
  10. Anything the user Anything the user doesn't need doesn't need

    right right now now could be could be unnecessary. unnecessary. 4 . 6
  11. There are a ton of There are a ton of

    ways to split your ways to split your code. code. 4 . 8
  12. SSR Alternatives SSR Alternatives : modern recommended approach : older

    approach; issues with latest webpack version No Code Splitting: Loadable Components React Loadable 5 . 3
  13. When not to lazy load. When not to lazy load.

    Login Forms and other frequently interacted with Components Whatever is most important on the page Limit number of JS files per page to something sensible (Note: HTTP2 was supposed to be a panacea where we could make dozens to hundreds of requests on the same pipe and things would be great; that isn't necessarily the case in the real world.) 5 . 5
  14. Lazy loading can Lazy loading can prevent or delay user

    prevent or delay user interaction. interaction. 5 . 6
  15. Don't block your users. Don't block your users. Waiting to

    load something until the user tries to interact with it can produce a bad experience You can leverage preloading and prerendering techniques to gain the benefits of code splitting without the drawbacks of preventing interaction Consider if its possible to predict what a user will need and begin to load it just before they need it 5 . 7
  16. Dynamic imports are Dynamic imports are not really supported not

    really supported in React Native. in React Native. Yet. 5 . 8
  17. React Native React Native As far as I know, you're

    kind of out of luck on this one for now It is supposed to be in the works 5 . 9
  18. import React, { Suspense, lazy } from 'react'; const LazyComponent

    = lazy(() => import('../lazy-component')); export default () => ( <main> <h1>Lazy Component Below</h1> <Suspense fallback={<p>Loading...</p>}> <LazyComponent /> </Suspense> </main> ); Basic Example Basic Example 7 . 1
  19. import React, { Suspense, lazy } from 'react'; const LazyComponent

    = lazy(() => /* webpackChunkName: "lazy" */ import('../lazy-componen export default () => ( <main> <h1>Lazy Component Below</h1> <Suspense fallback={<p>Loading...</p>}> <LazyComponent /> </Suspense> </main> ); As a Named Chunk As a Named Chunk Note: We're going to leave the import statement and variable declaration out out in some later slides due to space constraints. 7 . 2
  20. export default class MyComponent extends Component { state = {

    showLazyComponent: false, }; render() { const { showLazyComponent } = this.state; return ( <main> <h1>Lazy Component Below</h1> <button type="button" onClick={() => this.setState({ showLazyComponent: !showLazyComponent })} > Toggle Lazy </button> {showLazyComponent && <Suspense fallback={<p>Loading...</p>}> <LazyComponent /> </Suspense> } </main> ); } } Lazy Load on Click Lazy Load on Click 7 . 3
  21. import React, { Component, Supsense, lazy } from 'react'; //

    this will create a new bundle that gets loaded after the current bundle const lazyComponentPromise = import(/* webpackChunkName: "lazy" */ '../lazy'); const LazyComponent = lazy(() => lazyComponentPromise); export default () => ( <main> <h1>Lazy Component Below</h1> <Suspense fallback={<p>Loading...</p>}> <LazyComponent /> </Suspense> </main> ); Code Splitting w/Preload Code Splitting w/Preload 7 . 4
  22. import { lazy } from 'react'; export default function lazyWithPreload(componentPromise)

    => { const Component = lazy(componentPromise); Component.preload = componentPromise; return Component; }; Developer Defined Preload Developer Defined Preload Note: We'll use this in the next slide. 7 . 5
  23. import React, { Component, Suspense } from 'react'; import lazyWithPreload

    from '../lazy-with-preload'; const LazyComponent = lazyWithPreload(() => import('../lazy')); export default class MyComponent extends Component { state = { showLazyComponent: false, }; lazyLoad = () => { LazyComponent.preload(); this.setState({ showLazyComponent: !this.state.showLazyComponent }); }; render() { const { showLazyComponent } = this.state; return ( <main> <button type="button" onClick={this.lazyLoad}>Toggle Lazy</button> {this.state.showLazyComponent && <Suspense fallback={<p>Loading...</p>}> <LazyComponent /> </Suspense> } </main> ); } } 7 . 6