useAsync
مدیریت وضعیت یک عملیات async (loading / data / error) بدون کتابخانهی سنگین
معرفی
هوک useAsync هوکِ دادهی همهی نمونههای صفحه (راهنمای مصرف و اپ شروع) است: data، error و وضعیت درخواست را نگه
میدارد و یک تابعِ پایدارِ run میدهد؛ اگر در حین یک درخواست، درخواستِ تازهای run شود، نتیجهی قدیمی نادیده گرفته
میشود (بدون race). عمداً کوچک است: cache، حذفِ درخواستهای تکراری و retry خودکار ندارد.
استفاده
در صفحه، خروجی هوک را به state قالب صفحه بدهید — pageState از آن یک پاسخ برای
بارگذاری، خطا، خالی و آماده میسازد (نخستین رندرِ idle هم بارگذاری است). هرگز روی status شاخه نزنید تا اسکلت یا
خطای خودتان را بکشید، و هوک را از هیچ شروع کنید (useAsync<T>()، بی initialData): [] اولیه یعنی فهرست خالیِ
بارشده.
'use client'
import * as React from 'react'
import { DataTable, useAsync, type DataTableColumn } from '@partodata/ui'
import { ListPage, pageState } from '@partodata/ui/templates'
type Source = { id: string; name: string }
// درخواست API اپ، در سطح ماژول (پس `load` پایین میان رندرها همان تابع میماند)
async function getSources(q: string): Promise<Source[]> {
const response = await fetch(`/api/sources?q=${encodeURIComponent(q)}`)
if (!response.ok) throw new Error(`sources: ${response.status}`)
return response.json()
}
const columns: DataTableColumn<Source>[] = [{ id: 'name', header: 'منبع', cell: (row) => row.name }]
export function Sources({ q }: { q: string }) {
const { data, isLoading, error, run } = useAsync<Source[]>()
// مقدارهای درخواست در خود فراخوانی، همان مقدارها در وابستگیها
const load = React.useCallback(() => run(() => getSources(q)), [run, q])
React.useEffect(() => {
load()
}, [load])
return (
<ListPage
title="منبعها"
state={pageState({ data, isLoading, error, onRetry: load, emptyCopy: { title: 'هنوز منبعی ثبت نشده است' } })}
>
<DataTable columns={columns} data={data ?? []} />
</ListPage>
)
}وابستگیهای load: مقدارهای درخواست را در خود فراخوانی بگذارید و همان وضعیتها (useState، useDebounce) را در
وابستگیها — هرگز شیئی که هنگام رندر ساخته شود (const params = { q, page } و بعد [run, params]): شیء تازه در هر
رندر یعنی load تازه در هر رندر، و صفحه بیپایان درخواست میفرستد. run خودش پایدار است.
پارامترها
امضا: useAsync<T = unknown>(initialData?) — نوع نتیجه را با جنریک T مشخص کنید (مثل useAsync<User>()).
| پارامتر | نوع | پیشفرض | توضیح |
|---|---|---|---|
initialData | T | null | null | مقدار اولیهی data — پیش از اولین run و پس از reset همین مقدار برمیگردد |
مقدار بازگشتی
| فیلد | نوع | توضیح |
|---|---|---|
data | T | null | نتیجهی آخرین عملیاتِ موفق |
error | unknown | خطای آخرین عملیات |
status | 'idle' | 'loading' | 'success' | 'error' | وضعیتِ فعلی |
isLoading | boolean | میانبُرِ status === 'loading' (و مشابه برای بقیه) |
run | (op: () => Promise<T>) => Promise<T | undefined> | اجرای عملیات؛ نتیجهی قبلیِ در حالِ اجرا را لغو میکند |
reset | () => void | بازگشت به حالتِ idle |
هوکهای مرتبط
- حالتهای بارگذاری، خطا و خالیِ یک صفحه یا یک بخش → PageState / pageState
- صفحهٔ فهرست با جستوجو، فیلتر و صفحهبندی → ListPage