elements
lifecycle
browser
- useAudio
- useBattery
- useBluetooth
- useBreakpoints
- useBroadcastChannel
- useBrowserLocation
- useClipboard
- useCopy
- useCssVar
- useDisplayMedia
- useDocumentEvent
- useDocumentTitle
- useDocumentVisibility
- useEventListener
- useEventSource
- useEyeDropper
- useFavicon
- useFileSystemAccess
- useFps
- useFullscreen
- useGamepad
- useGeolocation
- useMeasure
- useMediaControls
- useMediaQuery
- useMemory
- useNetwork
- useObjectUrl
- useOnline
- useOtpCredential
- usePermission
- usePictureInPicture
- usePointerLock
- usePostMessage
- useRaf
- useShare
- useSpeechRecognition
- useSpeechSynthesis
- useSticky
utilities
state
user
sensors
0 Pokémon in this generation
import { useQuery } from '@siberiacancode/reactuse';
import { useState } from 'react';
import { cn } from '@/utils/lib';
interface Pokemon {
id: number;
name: string;
}
interface Generation {
pokemon_species: { name: string; url: string }[];
}
const GENERATIONS = [
{ id: 1, label: 'Gen I' },
{ id: 2, label: 'Gen II' },
{ id: 3, label: 'Gen III' },
{ id: 4, label: 'Gen IV' }
];
const getIdFromUrl = (url: string) => {
const parts = url.split('/').filter(Boolean);
return Number(parts[parts.length - 1]);
};
const getImageUrl = (id: number) =>
`https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${id}.png`;
const fetchGeneration = async (generation: number): Promise<Pokemon[]> => {
await new Promise((resolve) => setTimeout(resolve, 800));
const data = (await fetch(`https://pokeapi.co/api/v2/generation/${generation}`).then((res) =>
res.json()
)) as Generation;
return data.pokemon_species
.map((species) => ({ name: species.name, id: getIdFromUrl(species.url) }))
.sort((a, b) => a.id - b.id);
};
const Demo = () => {
const [generation, setGeneration] = useState(1);
const pokemonQuery = useQuery(() => fetchGeneration(generation), {
keys: [generation]
});
const loading = pokemonQuery.isLoading || pokemonQuery.isRefetching;
const pokemon = pokemonQuery.data ?? [];
return (
<section className='flex w-full max-w-md flex-col gap-3 p-4'>
<div className='bg-muted flex items-center gap-0.5 self-start rounded-lg p-0.5'>
{GENERATIONS.map((item) => (
<button
key={item.id}
className={cn(
'rounded-md! px-3 py-1 text-xs font-medium transition-colors',
generation === item.id ? 'bg-background shadow-sm' : 'text-muted-foreground'
)}
data-variant='unstyled'
type='button'
onClick={() => setGeneration(item.id)}
>
{item.label}
</button>
))}
</div>
<div className='no-scrollbar h-[340px] overflow-y-auto'>
<div className='grid auto-rows-[112px] grid-cols-2 gap-2 sm:auto-rows-[96px] sm:grid-cols-4'>
{loading &&
Array.from({ length: 12 }, (_, index) => (
<div
key={index}
className='border-border bg-card h-full animate-pulse rounded-xl border p-2'
/>
))}
{!loading &&
pokemon.map((item) => (
<div
key={item.id}
className='border-border bg-card hover:bg-muted/40 flex h-full flex-col items-center justify-center gap-1 overflow-hidden rounded-xl border p-2 transition-colors'
>
<img
alt={item.name}
className='size-16 object-contain'
loading='lazy'
src={getImageUrl(item.id)}
/>
<span className='text-muted-foreground font-mono text-[10px] tabular-nums'>
#{String(item.id).padStart(3, '0')}
</span>
<span className='text-foreground w-full truncate text-center text-xs font-medium capitalize'>
{item.name}
</span>
</div>
))}
</div>
</div>
<p className='text-muted-foreground text-center text-xs'>
{loading ? 'Loading Pokémon…' : `${pokemon.length} Pokémon in this generation`}
</p>
</section>
);
};
export default Demo;
Installation
pnpm add @siberiacancode/reactuseUsage
const { data, isFetching, isLoading, isError, isSuccess, error, refetch, isRefetching, abort, aborted } = useQuery(() => fetch('url'));Type Declarations
import type { DependencyList } from 'react';
export interface UseQueryOptions<QueryData, Data> {
/* The enabled state of the query */
enabled?: boolean;
/* The depends for the hook */
keys?: DependencyList;
/* The placeholder data for the hook */
placeholderData?: (() => Data) | Data;
/* The refetch interval */
refetchInterval?: number;
/* The retry count of requests */
retry?: boolean | number;
/* The retry delay of requests */
retryDelay?: ((retry: number, error: Error) => number) | number;
/* The callback function to be invoked on error */
onError?: (error: Error) => void;
/* The callback function to be invoked on success */
onSuccess?: (data: Data) => void;
/* The select function to be invoked */
select?: (data: QueryData) => Data;
}
interface UseQueryCallbackParams {
/* The depends for the hook */
keys: DependencyList;
/* The abort signal */
signal: AbortSignal;
}
export interface UseQueryReturn<Data> {
/* The abort function */
abort: AbortController['abort'];
/* The state of the query */
data?: Data;
/* The success state of the query */
error?: Error;
/* The error state of the query */
isError: boolean;
/* The fetching state of the query */
isFetching: boolean;
/* The loading state of the query */
isLoading: boolean;
/* The refetching state of the query */
isRefetching: boolean;
/* The success state of the query */
isSuccess: boolean;
/* The fetch promise function */
fetch: () => Promise<void>;
/* The refetch function */
refetch: () => void;
}API
Parameters
| Name | Type | Default | Note |
|---|---|---|---|
| callback | () => Promise<Data> | - | The callback function to be invoked |
| options.keys | DependencyList | - | The dependencies for the hook |
| options.onSuccess | (data: Data) => void | - | The callback function to be invoked on success |
| options.onError | (error: Error) => void | - | The callback function to be invoked on error |
| options.select | UseQueryOptionsSelect<Data> | - | The select function to be invoked |
| options.initialData | Data | (() => Data) | - | The initial data for the hook |
| options.placeholderData | Data | (() => Data) | - | The placeholder data for the hook |
| options.refetchInterval | number | - | The refetch interval |
| options.retry | boolean | number | - | The retry count of requests |
Returns
UseQueryReturn<Data>Contributors
ddebabinVVitaly StatsuraVVitaly Statsurahhywax
Last updated on