async
lifecycle
browser
utilities
Loading evolution chain
import { useAsyncEffect, useBoolean, useToggle } from '@siberiacancode/reactuse';
import { Loader2Icon } from 'lucide-react';
import { Fragment, useState } from 'react';
import { cn } from '@/utils/lib';
interface Pokemon {
id: number;
name: string;
}
const CHAINS = {
bulbasaur: [1, 2, 3],
charmander: [4, 5, 6],
squirtle: [7, 8, 9]
};
const getPokemons = async (ids: number[]) => {
await new Promise((resolve) => setTimeout(resolve, 1000));
return Promise.all(
ids.map((id) => fetch(`https://pokeapi.co/api/v2/pokemon/${id}`).then((res) => res.json()))
);
};
const Demo = () => {
const [chain, toggleChain] = useToggle<keyof typeof CHAINS>([
'bulbasaur',
'charmander',
'squirtle'
]);
const [pokemons, setPokemons] = useState<Pokemon[]>([]);
const [isLoading, setIsLoading] = useBoolean(true);
useAsyncEffect(async () => {
setIsLoading(true);
const data = await getPokemons(CHAINS[chain]);
setPokemons(data);
setIsLoading(false);
}, [chain]);
return (
<section className='flex min-w-xs flex-col gap-4 md:min-w-md'>
<div data-slot='tabs'>
<div className='mb-6' data-slot='tabs-list'>
{Object.keys(CHAINS).map((name) => (
<button
key={name}
data-state={cn(chain === name && 'active')}
data-variant='tabs-trigger'
type='button'
onClick={() => toggleChain(name as keyof typeof CHAINS)}
>
{name}
</button>
))}
</div>
<div data-slot='tabs-content rounded-lg border'>
{isLoading && (
<div className='flex h-36 flex-col items-center justify-center gap-2'>
<Loader2Icon className='size-6 animate-spin' />
<p>
Loading <code>evolution</code> chain
</p>
</div>
)}
{!isLoading && (
<div className='flex h-36 flex-row items-center justify-between gap-2'>
{pokemons.map((pokemon, index) => (
<Fragment key={pokemon.id}>
<div className='flex flex-col items-center gap-2'>
<div className='flex size-20 items-center justify-center md:size-28'>
<img
alt={pokemon.name}
className='h-20 md:h-28'
src={`https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/${pokemon.id}.png`}
/>
</div>
<p className='text-sm capitalize'>{pokemon.name}</p>
</div>
{index < pokemons.length - 1 && <div className='text-xl'>{'>'}</div>}
</Fragment>
))}
</div>
)}
</div>
</div>
</section>
);
};
export default Demo;
Installation
pnpm add @siberiacancode/reactuseUsage
useAsyncEffect(async () => console.log("effect runs on updates"), deps);Type Declarations
import type { DependencyList } from 'react';API
Parameters
| Name | Type | Default | Note |
|---|---|---|---|
| effect | EffectCallback | - | The effect callback |
| deps | DependencyList | - | The dependencies list for the effect |
Contributors
ddebabin
Last updated on