• صفحه اصلی
  • درباره من
  • مهارت‌های ایجنت
  • پروژه‌ها
  • بلاگ
  • مشاوره
  • تماس با من
مشاورهرزومه
Naser Rasouli

نویسنده

Naser Rasouli

توسعه‌دهنده فرانت‌اند؛ اینجا تجربه‌ها و یادداشت‌های واقعی‌ام از پروژه‌ها را می‌نویسم.

GitHubLinkedIn

آخرین نوشته‌ها

دیباگ INP در اپ‌های React از Field Data تا Profiler
2026-09-10•1 دقیقه مطالعه

دیباگ INP در اپ‌های React از Field Data تا Profiler

یک روند عملی برای پیدا کردن interactionهای کند در React؛ از Field Data و Long Task تا React Profiler، event handlerهای سنگین و کاهش کار روی main thread.

JavaScript SEO برای React: Google دقیقاً چه چیزی می‌بیند؟
2026-09-10•1 دقیقه مطالعه

JavaScript SEO برای React: Google دقیقاً چه چیزی می‌بیند؟

راهنمای عملی JavaScript SEO در React؛ تفاوت crawl و render و index، انتخاب SSR یا prerender و جلوگیری از پنهان‌شدن محتوا و لینک‌ها پشت client rendering.

فرم‌های Type-safe در React با React Hook Form و Zod
2026-09-07•1 دقیقه مطالعه

فرم‌های Type-safe در React با React Hook Form و Zod

یک الگوی schema-first برای ساخت فرم‌های React با React Hook Form و Zod؛ از type inference و field array تا خطاهای API و مرز validation سمت کلاینت و سرور.

Optimistic UI در React بدون باگ‌های رایج

Optimistic UI در React بدون باگ‌های رایج

2026-09-11
reactoptimistic-uiuseOptimistictransitionsux

Optimistic UI در React بدون باگ‌های رایج

Optimistic UI یعنی رابط کاربری قبل از تمام‌شدن درخواست سرور، نتیجه‌ای را نشان دهد که انتظار داریم موفق شود. این الگو برای Like، تغییر وضعیت، اضافه‌کردن آیتم و عملیات کوتاه بسیار مفید است؛ اما اگر state خوش‌بینانه را با state واقعی اشتباه بگیریم، خیلی زود با rollback ناقص، داده تکراری و race condition روبه‌رو می‌شویم.

در React، useOptimistic برای ساخت یک نمای موقت از state طراحی شده است. نکته مهم این است که سرور همچنان منبع حقیقت باقی می‌ماند.

1. اول مشخص کنید چه چیزی واقعاً Optimistic است

هر Mutation مناسب Optimistic UI نیست. عملیات مناسب معمولاً نتیجه قابل پیش‌بینی، شکست نادر و rollback قابل‌فهم دارد. برای انتقال پول، ثبت سفارش حساس یا عملیاتی که سرور ممکن است نتیجه‌ای کاملاً متفاوت بسازد، بهتر است UI را بیش از حد خوش‌بینانه نکنید.

2. State واقعی را دوباره نسازید

import { startTransition, useOptimistic } from "react"

type Comment = { id: string; body: string; pending?: boolean }

function Comments({ comments }: { comments: Comment[] }) {
  const [optimisticComments, addOptimisticComment] = useOptimistic(
    comments,
    (current, draft: Comment) => [...current, draft],
  )

  async function submit(body: string) {
    const temporary = { id: crypto.randomUUID(), body, pending: true }
    startTransition(async () => {
      addOptimisticComment(temporary)
      await createComment({ body })
    })
  }

  return optimisticComments.map((comment) => (
    <article key={comment.id} aria-busy={comment.pending}>{comment.body}</article>
  ))
}

useOptimistic یک state موقت برای دوره انجام Action می‌سازد. وقتی داده واقعی جدید برسد، UI باید دوباره با منبع حقیقت همگام شود.

3. شناسه موقت را با شناسه سرور یکی نگیرید

اگر سرور id تولید می‌کند، برای آیتم pending یک شناسه موقت مستقل بسازید. بعد از موفقیت، داده authoritative سرور باید جای نسخه موقت را بگیرد. نگه‌داشتن هم‌زمان آیتم optimistic و append کردن پاسخ سرور یکی از علت‌های رایج duplicate است.

4. شکست را بخشی از طراحی UI بدانید

rollback فقط برگرداندن مقدار نیست. کاربر باید بفهمد چه اتفاقی افتاده و در صورت امکان بتواند دوباره تلاش کند. برای فرم‌های طولانی، حذف دائمی یا عملیات چندمرحله‌ای، نگه‌داشتن draft کاربر معمولاً بهتر از پاک‌کردن همه‌چیز بعد از خطاست.

5. Mutationهای هم‌زمان را جدی بگیرید

اگر کاربر چند Action پشت‌سرهم اجرا کند، ترتیب پاسخ‌ها ممکن است با ترتیب کلیک‌ها یکی نباشد. مشخص کنید Actionها مستقل‌اند، آخرین درخواست باید برنده باشد، سرور version authoritative دارد یا باید Action تکراری را موقتاً غیرفعال کرد.

6. Transition جای Error Handling نیست

Transition به React کمک می‌کند آپدیت غیرضروری برای تعامل فوری را مدیریت کند؛ اما مسئول retry، rollback یا اعتبارسنجی پاسخ سرور نیست.

User intent
   ↓
Optimistic projection
   ↓
Server mutation
   ↓
Success → authoritative data
Failure → feedback / rollback / retry

7. با Server State Library مرز روشنی داشته باشید

اگر داده با TanStack Query یا ابزار مشابه مدیریت می‌شود، دو سیستم optimistic مستقل برای یک Resource نسازید. یک Feature باید یک مالک روشن برای lifecycle داده داشته باشد.

چک‌لیست نهایی

قبل از انتشار بررسی کنید سرور منبع حقیقت مانده، pending state مشخص است، شکست feedback دارد، پاسخ سرور duplicate نمی‌سازد، Actionهای هم‌زمان تست شده‌اند و state موازی غیرضروری وجود ندارد.

Optimistic UI زمانی خوب است که latency را پنهان کند، نه حقیقت سیستم را. هرچه reconciliation پیچیده‌تر می‌شود، دوباره بررسی کنید که آیا این عملیات اصلاً باید optimistic باشد یا نه.