suspendable
suspendable
is a set of utilities to create resources that can suspend in React.
Suspendable resources are meant to be used with React <Suspense>
(added in React 16.6) to decleratively wait while they're loading and show a fallback.
When using a suspendable resource inside a React component, you can treat it as it already loaded - there's no need to check if it loaded or not because if it did not load when you try to use it, the React component will suspend and show the fallback of the nearest <Suspense>
ancestor.
Installation
Using yarn:
yarn add suspendable
Using npm:
npm install suspendable
API
lazyResource
Resource
ResourceOptions
clearResourceErrors
lazyComponent
preloadLazyComponent
clearLazyComponentError
lazyResource
lazyResource<T>(loader: () => Promise<T>, options?: ResourceOptions): Resource<T>
Parameters
-
loader
is the loader function to load a resource of typeT
. This is a regular function that returns a promise. -
options?: ResourceOptions
are the resource options.
Return value
-
Resource<T>
a resource of typeT
.
Description
lazyResource
is used to create a lazy resource. It's lazy because it will not start loading the resource immediately. Instead, it will start loading it only when the load
method is called. The resource can be read at any point inside a React component - if it has not loaded at the time it is read, the component will suspend.
Example
const resource = lazyResource(() => import('./data.json'), { autoRetry: true });
// start loading it at some point later
resource.load();
// read it inside a React component
resource.read();
Resource
interface Resource<T> {
clearError: () => void;
get: () => T | null;
load: () => Promise<T>;
read: () => T;
}
-
clearError: () => void
clears the error in case the resource failed to load. This allows to call the load method again and retry loading the resource. This method has no effect if the resource is still loading or if it already loaded successfully. -
get: () => T | null
returns the loaded resource ornull
if the resource is still loading, if it failed to load, or if it didn't even start loading yet. -
load: () => Promise<T>
begins loading the resource by calling the provided loader function. This method is idempotent - calling it after the first time has no effect. However, If the resource fails to load andResource#clearError()
is called (orclearResourceErrors
), then calling this method will again begin loading the resource. -
read: () => T
returns the loaded resource. If the resource is still loading when this method is called, it will throw the resource promise, which will make the React component suspend and show the fallback of the nearest<Suspense>
ancestor. If the resource failed to load, then this method will throw the error with which the promise rejected, causing the fallback of the nearest error boundary ancestor to be shown, if any. This method must be called inside a React component and it can only be called after the resource started loading withResource#load()
.
ResourceOptions
interface ResourceOptions {
autoRetry?: boolean;
autoRetryTimeoutMs?: number;
}
-
autoRetry?: boolean
(defaultfalse
) specifies whether to retry loading the resource if it fails to load the first time. When set totrue
and the promise returned by the loader function rejects, it will waitautoRetryTimeoutMs
milliseconds and call the loader again. It will keep doing this until the promise returned by the loader resolves. -
autoRetryTimeoutMs?: number
(default3000
) the number of milliseconds to wait before retrying calling the loader after the promise that the loader previosly returned rejects. This option is applicable only whenautoRetry
is set totrue
.
clearResourceErrors
clearResourceErrors(): void
Description
clearResourceErrors
clears the errors for all resources that failed to load. This means that all those resource can retry loading by calling the Resource#load()
method.
lazyComponent
lazyComponent<P>(loader: () => Promise<{ default: ComponentType<P> }>, options?: ResourceOptions): ComponentType<P>
Parameters
-
loader
is the loader function to load a React component. This is a function that returns a dynamic import. The component should be the default export of the module that is dynamically imported. -
options?: ResourceOptions
are the resource options.
Return value
-
ComponentType<P>
a lazy React component that accepts exactly the same props as the component being dynamically imported.
Description
lazyComponent
is a wrapper around lazyResource
that is used to create a lazy React component. It's lazy because it will not start loading the original component immediately. Instead, it will start loading it only when the component is being rendered or when preloadLazyComponent
is called. The component can be rendered at any point; if it has not loaded at the time it is rendered, it will suspend.
lazyComponent
is very similar to React.lazy
, but has a few key differences:
-
React.lazy
will start loading the component when it is rendered. There is no easy way to start loading it earlier.lazyComponent
returns a lazy component that can start loading even before being rendered (by callingpreloadLazyComponent
). -
lazyComponent
accepts options that allow to auto-retry loading the component in case it fails to load the first time. -
React.lazy
will cache the promise returned by the loader function even if the promise rejects. So, it the component fails to load, there's no easy way to retry loading it. WithlazyComponent
this can be easily accomplished by callingclearLazyComponentError
(orclearResourceErrors
, which will clear errors for all resources that failed to load).
Example
const LazyWidget = lazyComponent(() => import('./components/Widget'), {
autoRetry: true,
});
// optionally start preloading it at any point
preloadLazyComponent(LazyWidget);
// render it at any point
return <LazyWidget {...widgetProps} />;
preloadLazyComponent
preloadLazyComponent(LazyComponent: ComponentType<any>): void
Parameters
-
LazyComponent
the lazy component returned bylazyComponent
that we want to preload.
Description
preloadLazyComponent
preloads a lazy component, i.e., starts loading the lazy component even before it is rendered. Good places where to start preloading a component are the router and event handlers. Under the hood, this function is just calling Resource#load()
for the component resource, which means that it is idempotent - calling it after the first time has no effect. However, If the component fails to load and clearLazyComponentError
is called (or clearResourceErrors
), then calling this method will again begin loading the component.
clearLazyComponentError
clearLazyComponentError(LazyComponent: ComponentType<any>): void
Parameters
-
LazyComponent
the lazy component returned bylazyComponent
for which we want to clear the error.
Description
clearLazyComponentError
clears the error for a lazy component that failed to load. This allows rendering the component again and calling preloadLazyComponent
to retry loading the component. This function has no effect if the component is still loading or if it already loaded successfully.
Prior art
This library was inspired by JSResource
as defined here.
Contributing
Pull requests are very welcome. If you intend to introduce a major change, please open a related issue first in which we can discuss what you would like to change.
Please make sure to update the tests and the README as appropriate.