Skip to content

Instantly share code, notes, and snippets.

@karpolan
Created August 10, 2019 10:46
Show Gist options
  • Save karpolan/80cf28cb742851fcb3abb7796c4f7fdc to your computer and use it in GitHub Desktop.
Save karpolan/80cf28cb742851fcb3abb7796c4f7fdc to your computer and use it in GitHub Desktop.
withSuspense() HOC for React.lazy() + React.Suspense
import React from 'react';
import { CircularProgress, LinearProgress } from '@material-ui/core/';
/**
* Wraps the React Component with React.Suspense and FallbackComponent while loading.
* @param {React.Component} WrappedComponent - lazy loading component to wrap.
* @param {React.Component} FallbackComponent - component to show while the WrappedComponent is loading.
*/
export const withSuspense = (WrappedComponent, FallbackComponent = null) => {
return class extends React.Component {
render() {
if (!FallbackComponent) FallbackComponent = <LinearProgress />; // by default
return (
<React.Suspense fallback={FallbackComponent}>
<WrappedComponent {...this.props} />
</React.Suspense>
);
}
};
};
...
// Usage
const lazySomeComponent = React.lazy(() => import('./xxx/SomeComponent'));
export const SomeComponent = withSuspense(lazySomeComponent);
export const SomeComponentWithCircularProgress = withSuspense(lazySomeComponent, <CircularProgress />);
export const SomeComponentWithDiv = withSuspense(lazySomeComponent, <div>Loading...</div>);
@UladzKha
Copy link

UladzKha commented Dec 30, 2021

Hey, thanks for this!
I have small suggestion: you can replace null with <LinearProgress /> in ...withSuspense = (WrappedComponent, FallbackComponent = <LinearProgress />) => ....

and you can get rid of check if its null if (!FallbackComponent) FallbackComponent = <LinearProgress />; // by default

@karpolan
Copy link
Author

Could be :)

@UladzKha
Copy link

UladzKha commented Dec 30, 2021

@karpolan could you please help me ? Can I move import logic into the HOC ? I mean to move const lazySomeComponent = React.lazt(() => import('path')); into the withSuspense method?

@karpolan
Copy link
Author

karpolan commented Dec 30, 2021

You can, but in that case you need await loading...

I suggest to use following way:

import React from 'react';

/**
 * Note: Don't import/export all Views directly, use lazy loading!
 */
import { withSuspense } from '../components';
import NotFound from './NotFound';

/**
 * Views/Pages with Lazy Loading
 */
const Welcome = withSuspense(React.lazy(() => import('./Welcome')));
const About = withSuspense(React.lazy(() => import('./About')));
const MyProfile = withSuspense(React.lazy(() => import('./MyProfile')));

export { NotFound, Welcome, MyProfile, About };

@UladzKha
Copy link

@karpolan many thanks!

@mz8i
Copy link

mz8i commented Jul 23, 2023

Nice! A comment on the naming - the argument you pass to Suspense's fallback prop is not actually a React component - it's a tree of React elements, in TS typed as ReactNode. So the naming FallbackComponent (capitalised, with "Component") is actually misleading - note you never write <FallbackComponent />. A better name for the second argument of the HOC would be simply fallback, or fallbackElement.

@Lazeta
Copy link

Lazeta commented Dec 25, 2024

or for functional component :


import React from 'react';
import { CircularProgress, LinearProgress } from '@material-ui/core/';

/**

  • Wraps the React Component with React.Suspense and FallbackComponent while loading.
  • @param {React.Component} WrappedComponent - lazy loading component to wrap.
  • @param {React.Component} FallbackComponent - component to show while the WrappedComponent is loading.
    */
    const withSuspense = (WrappedComponent, FallbackComponent = ) => {
    return (props) => (
    <React.Suspense fallback={FallbackComponent}>
    <WrappedComponent {...props} />
    </React.Suspense>
    );
    };

// Usage
const lazySomeComponent = React.lazy(() => import('./xxx/SomeComponent'));

export const SomeComponent = withSuspense(lazySomeComponent);
export const SomeComponentWithCircularProgress = withSuspense(lazySomeComponent, );
export const SomeComponentWithDiv = withSuspense(lazySomeComponent,

Loading...
);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment