dmwong2268
dmwong2268

Reputation: 3575

React.lazy and prefetching components

I have a 2 step Application Flow that looks like this:

const Step1 = React.lazy(() => import('./Step1'));
const Step1 = React.lazy(() => import('./Step2'));

<Suspense fallback={<Loading />}>
  <Route path="/step1" render={() => <Step1 />} />
  <Route path="/step2" render={() => <Step2 />} />
</Suspense>

Using React.lazy, I can defer loading <Step2 /> while the user is on <Step1 />, which can improve initial page load. However, I would like to prefetch <Step2 /> while the user is on <Step1 /> as an optimization. Is there an API to do this with React.lazy?

Edit:

To elaborate - I'm using a router to render a 2 step form. Initially the user will start on /step1. After the user completes all the tasks in <Step1 /> they will be routed to path /step2. At this point the router will render the <Step2 /> component.

I'm asking if there is a pattern to pre-fetch <Step2 /> while the user is still on <Step1 />.

Upvotes: 9

Views: 12547

Answers (3)

EHF32
EHF32

Reputation: 26

For anyone interested, I added types to Yash Joshi's answer.

import React, { ComponentType, LazyExoticComponent } from "react";

type PreloadableComponent<T extends ComponentType<any>> =
  LazyExoticComponent<T> & {
    preload: () => Promise<void>;
  };

function lazyWithPreload<T extends ComponentType<any>>(
  factory: () => Promise<{ default: T }>
): PreloadableComponent<T> {
  const Component: Partial<PreloadableComponent<T>> = React.lazy(factory);

  Component.preload = async () => {
    await factory();
  };

  return Component as PreloadableComponent<T>;
}

export default lazyWithPreload;

Upvotes: 1

maddhruv
maddhruv

Reputation: 987

I wrote a small wrapper function around React lazy to handle missing assets, we can tweak that a little bit to easily add support for prefetching.

// Lazy with Retry and Prefetching
export const lazyWithRetryAndPrefetching = (componentImport) => {
  const factory = async () => {
    try {
      return await componentImport();
    } catch (error) {
      console.error(error);
      return window.location.reload();
    }
  };

  const Component = lazy(factory);

  Component.prefetch = factory;

  return Component;
};

and prefetching on demand is as easy as

// App.jsx
const Material = lazyWithRetryAndPrefetching(() => import("./Material"));

useEffect(() => {
    Material.prefetch();
}, []);

More details are posted on my blogs

Upvotes: -1

Yash Joshi
Yash Joshi

Reputation: 2774

I was also reading about this few days back and I liked this approach:

Enhance the React.lazy to have a callback that can be used to load the component. Something like this:

function lazyWithPreload(factory) {
  const Component = React.lazy(factory);
  Component.preload = factory;
  return Component;
}

const ComponentToPreload = lazyWithPreload(() => import("./Component"));

/* usage in Component */

ComponentToPreload.preload(); // this will trigger network request to load the component


In this way, you can preload the component wherever you want. Like on click event or after the current component has Mounted.

Must read the original post: https://medium.com/hackernoon/lazy-loading-and-preloading-components-in-react-16-6-804de091c82d


If you are using react-loadable. You can check this: https://github.com/jamiebuilds/react-loadable#preloading

Hope this helps!

Upvotes: 28

Related Questions