async
lifecycle
browser
utilities
001
Loading
import { useAsync, useCounter } from '@siberiacancode/reactuse';
import { ArrowLeftIcon, ArrowRightIcon, Loader2Icon } from 'lucide-react';
interface Pokemon {
base_experience: number;
height: number;
id: number;
name: string;
weight: number;
}
const getPokemon = async (id: number) => {
await new Promise((resolve) => setTimeout(resolve, 1000));
if (id === 3) throw new Error('Pokemon blocked for demo');
return fetch(`https://pokeapi.co/api/v2/pokemon/${id}`).then((res) =>
res.json()
) as Promise<Pokemon>;
};
const Demo = () => {
const counter = useCounter(1);
const getPokemonQuery = useAsync(() => getPokemon(counter.value), [counter.value]);
const formattedIndex = String(counter.value).padStart(3, '0');
return (
<section className='flex flex-col gap-4'>
<div className='flex items-center justify-between gap-4'>
<p className='font-mono font-bold'>{formattedIndex}</p>
<div className='flex gap-2'>
<button
disabled={counter.value === 1 || getPokemonQuery.isLoading}
type='button'
onClick={() => counter.dec()}
>
<ArrowLeftIcon className='size-4' /> Prev
</button>
<button disabled={getPokemonQuery.isLoading} type='button' onClick={() => counter.inc()}>
Next <ArrowRightIcon className='size-4' />
</button>
</div>
</div>
<div className='w-full min-w-xs rounded-lg border p-4 md:min-w-md'>
{getPokemonQuery.isLoading && (
<div className='flex h-32 flex-col items-center justify-center gap-2 md:h-44'>
<Loader2Icon className='size-5 animate-spin' />
<p>Loading</p>
</div>
)}
{getPokemonQuery.error && !getPokemonQuery.isLoading && (
<div className='flex h-32 items-center justify-center md:h-44'>
<p className='text-destructive'>{getPokemonQuery.error.message}</p>
</div>
)}
{getPokemonQuery.data && !getPokemonQuery.isLoading && !getPokemonQuery.error && (
<div className='flex items-center justify-center gap-6 md:gap-10'>
<div className='flex size-32 items-center justify-center md:size-44'>
<img
alt={getPokemonQuery.data.name}
className='h-32 md:h-44'
src={`https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/${getPokemonQuery.data.id}.png`}
/>
</div>
<div className='flex flex-col gap-2 text-sm md:text-base'>
<p>
name: <code>{getPokemonQuery.data.name}</code>
</p>
<p>
height: <code>{getPokemonQuery.data.height}</code>
</p>
<p>
weight: <code>{getPokemonQuery.data.weight}</code>
</p>
<p>
experience: <code>{getPokemonQuery.data.base_experience}</code>
</p>
</div>
</div>
)}
</div>
</section>
);
};
export default Demo;
Installation
pnpm add @siberiacancode/reactuseUsage
const { data, isLoading, isError, error } = useAsync(() => fetch('url'), [deps]);Type Declarations
import type { DependencyList } from 'react';
export interface UseAsyncReturn<Data> {
/* The state of the query */
data?: Data;
/* The error of the query */
error?: Error;
/* The error state of the query */
isError: boolean;
/* The loading state of the query */
isLoading: boolean;
}API
Parameters
| Name | Type | Default | Note |
|---|---|---|---|
| callback | () => Promise<Data> | - | The async callback |
| deps | DependencyList | [] | The dependencies of the callback |
Returns
UseAsyncReturn<Data>Contributors
ddebabinbbabin
Last updated on