Async Handler
HOC that takes an async function and returns views for loading, no-data and error states. It accepts an optional method to check a cache before the async function is run.
This package has been deprecated in favor of more complete solutions like React Query.
Demo
https://npm-library-demo.vercel.app/async-handler
Install
- npm
- Yarn
- pnpm
npm install @unleashit/async-handler
yarn add @unleashit/async-handler
pnpm add @unleashit/async-handler
Required peer dependencies: react.
Example with render prop
import React from 'react';
import AsyncHandler from '@unleashit/async-handler';
class ColorList extends React.Component {
request() {
return new Promise((resolve) => {
setTimeout(() => {
resolve(['red', 'green', 'blue', 'yellow', 'orange', 'black', 'white']);
}, 1500);
});
}
render() {
return (
<AsyncHandler request={this.request}>
{(data) => <div>{data.join(', ')}</div>}
</AsyncHandler>
);
}
}
export default ColorList;
This will display default messages for loading, error or no results* as needed. Note that request
should return a promise with just the data part of the response so AsyncHandler can know when to display the no results component.
* no results meaning when an object with no keys or a zero length array is returned.
HOC example using cache and optional components
import { withAsyncHandler } from '@unleashit/async-handler';
import MySpinner from './spinner';
// data to fetch asynchronously, here for demo reasons
const users = [
{
id: 1,
name: 'joe',
age: 30,
},
{
id: 2,
name: 'judy',
age: 27,
},
];
// for demonstration, normally you might use
// Redux or another decoupled place to store the cache.
let userCache = null;
const UserList = ({ data }) => {
return (
<ul>
{data.map((item) => (
<li key={item.id}>
{item.name} is {item.age} years old.
</li>
))}
</ul>
);
};
export default withAsyncHandler({
request: () => {
return new Promise((resolve) => {
setTimeout(() => {
userCache = { users, cacheDate: new Date() };
resolve(users);
}, 1500);
});
},
cache: () => {
return userCache && new Date() - userCache.cacheDate <= 5 * 1000
? userCache.users
: null;
},
loaderComponent: <MySpinner foo={'bar'} />,
noResultsComponent: <div>No user{"'"}s found.</div>,
errorComponent: ({ error }) => (
<div>Oops, there was a problem: {JSON.stringify(error)}</div>
),
})(UserList);
CSS
By default, all components come with basic css styling in two formats: standard (BEM namespaced) and a CSS Module friendly version.
To use the standard version, import it like: import '@unleashit/async-handler/dist/async-handler.css'
. Or if you are using CSS Modules you can import css from '@unleashit/async-handler/dist/async-handler.module.css'
and provide to the cssModule
prop and/or use your own custom module targeting the internal class names.
See styling-and-theming for more info.
API
interface DefaultComponentProps {
cssModule?: {
[key: string]: string;
};
error?: any;
}
type DefaultComponent = (props?: DefaultComponentProps) => React.ReactNode;
interface Props {
request: () => Promise<any>;
cache: () => object | any[] | false | null;
loaderComponent: DefaultComponent;
noResultsComponent: DefaultComponent;
errorComponent: DefaultComponent;
cssModule?: { [key: string]: string };
children: (data: any) => any;
}
Name | Type | Description | default |
---|---|---|---|
request | () => Promise<any> | Called if cache function exists and doesn't return a falsy value | required |
cache | () => object | any[] | false | null | Optional function that should return a cache object or null (calls the request) | n/a |
noResultsComponent | () => React.ReactNode | React component to override default no results message | Nothing found. |
errorComponent | ({ error }: {error: any} ) => React.ReactNode | React component to override default error message | default message with error displayed |
loaderComponent | () => React.ReactNode | React component to override the default loader | Loading... |
cssModule | Recrord<string, string> | CSS Module object that optionally replaces default. Class names need to match expected names. | undefined |
children | (data: any) => any | Function to be called with data if request returns with results (AsyncHandler only) | n/a |