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>()).

پارامترنوعپیش‌فرضتوضیح
initialDataT | nullnullمقدار اولیه‌ی data — پیش از اولین run و پس از reset همین مقدار برمی‌گردد

مقدار بازگشتی

فیلدنوعتوضیح
dataT | nullنتیجه‌ی آخرین عملیاتِ موفق
errorunknownخطای آخرین عملیات
status'idle' | 'loading' | 'success' | 'error'وضعیتِ فعلی
isLoadingbooleanمیان‌بُرِ status === 'loading' (و مشابه برای بقیه)
run(op: () => Promise<T>) => Promise<T | undefined>اجرای عملیات؛ نتیجه‌ی قبلیِ در حالِ اجرا را لغو می‌کند
reset() => voidبازگشت به حالتِ idle

هوک‌های مرتبط

  • حالت‌های بارگذاری، خطا و خالیِ یک صفحه یا یک بخش → PageState / pageState
  • صفحهٔ فهرست با جست‌وجو، فیلتر و صفحه‌بندی → ListPage