Convert a promise returning function into a suspense compatible resource.
npm install react-use-resource
yarn add react-use-resource
Wrap an application into a ResourcesBoundary
component. All request results will be cached in there.
import { Suspense } from 'react';
import { ResourcesBoundary } from 'react-use-resource';
export function Application() {
return (
<ResourcesBoundary>
<Suspense fallback="Loading...">
<User />
</Suspense>
</ResourcesBoundary>
);
}
Declare a promise returning function in any convenient way.
interface IUser {
username: string;
}
export function getUser(id: number) {
return fetch(`.../users/${id}`).then(response => response.json<IUser>());
}
The useResource
hook takes a resource id, a promise returning function and a dependency list (which works simmilar to useEffect
hook) and returns a resource for a provided function. Returned resource has read
and refresh
methods.
import { useResource } from 'react-use-resource';
export function User() {
const resource = useResource('USER', getUser, [42]);
return (
<h1>{ resource.read().username }<h1>
);
};
Resource id should be unique for a rendered component tree. Variables from a dependency list are passed down to a function as an arguments. Cached resource is invalidated upon a component unmount.
Ideally, upon a dependency list change we want to cancel a previous outgoing request. In order to achieve this our function should return not a simple promise but a tuple of a promise and a cancellation function.
export function getUser(id: number): [Promise<IUser>, () => void] {
const controller = new AbortController();
const signal = controller.signal;
const promise = fetch(`.../users/${id}`, { signal }).then(response => response.json<IUser>());
return [promise, controller.abort];
}
Instead of useResource
we can use useLazyResource
hook. This way the resource will be requested only upon the read
or refresh
call.
We can pass a cache
property to ResourcesBoundary
. All data will be written to and read from this record.
const cache: Record<string, any> = {};
<ResourcesBoundary cache={cache}>
<Application />
</ResourcesBoundary>