Skip to content

Instantly share code, notes, and snippets.

@karpolan
Created August 10, 2019 10:46
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • 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.

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