Transition چیست: مفهوم پایه پیش از useTransition

در دو درس قبل، دیدیم Concurrent Rendering و Scheduler، زیرساختی فراهم می‌کنند که به‌روزرسانی‌ها بتوانند اولویت متفاوتی داشته باشند. در این درس، به مفهوم Transition می‌پردازیم: دقیقاً چه نوع به‌روزرسانی‌ای، «انتقالی» محسوب می‌شود و چرا این نام‌گذاری، معنادار است؛ پیش از این‌که در درس بعدی، Hook واقعی useTransition را ببینیم.

یادآوری تقسیم‌بندی درس قبل

در درس قبل، به‌روزرسانی‌ها را به دو دسته کلی تقسیم کردیم: فوری (نتیجه مستقیم یک تعامل که باید بی‌درنگ دیده شود) و انتقالی (تغییراتی که نتیجه‌شان مهم است، اما نیازی به کامل شدن بی‌وقفه ندارند). Transition، نام رسمی همین دسته دوم در React است.

چرا نام «Transition» انتخاب شده

Transition، به معنای «گذار» یا «انتقال»، به این ایده اشاره دارد که رابط کاربری، در حال گذار از یک وضعیت به وضعیت دیگر است؛ مثلاً از «نتایج جست‌وجوی قبلی» به «نتایج جست‌وجوی جدید». در طول این گذار، منطقی است که React بپرسد: «آیا باید همین الان، مرحله میانی این گذار را نشان دهم، یا بهتر است صبر کنم تا وضعیت نهایی آماده شود؟» این دقیقاً سؤالی است که ابزار useTransition، در درس بعدی، پاسخ آن را در اختیار برنامه‌نویس می‌گذارد.

یک مثال مفهومی: تغییر تب در یک صفحه

jsx
function ProfilePage() {
  const [tab, setTab] = useState("posts");

  return (
    <div>
      <button onClick={() => setTab("posts")}>پست‌ها</button>
      <button onClick={() => setTab("about")}>درباره</button>

      {tab === "posts" ? <PostsTab /> : <AboutTab />}
    </div>
  );
}

اگر PostsTab نسبتاً سنگین باشد (مثلاً هزاران آیتم را رندر می‌کند)، تغییر tab با setTab معمولی، یک به‌روزرسانی فوری محسوب می‌شود؛ یعنی React تلاش می‌کند بلافاصله نتیجه نهایی را نشان دهد، حتی اگر این کار کمی طول بکشد و در این مدت، کلیک‌های بعدی کاربر دیرتر پاسخ داده شوند. اگر همین تغییر tab به‌عنوان یک Transition علامت‌گذاری شود، به React اجازه می‌دهیم بگوید: «نیازی نیست این گذار، فوری و بدون وقفه باشد؛ تا وقتی آماده نشده، محتوای فعلی (یا یک وضعیت میانی مشخص) را نگه دار.»

تفاوت مهم با Debouncing یا Throttling

ممکن است این ایده با تکنیک‌های آشنای Debounce یا Throttle (که در برخی پروژه‌های جاوااسکریپت دیده‌اید) اشتباه گرفته شود؛ اما تفاوت اساسی دارند. Debounce/Throttle، با تأخیر یا محدود کردن مصنوعی زمان، سعی می‌کنند تعداد اجراها را کم کنند؛ اما Transition، هیچ تأخیر مصنوعی اضافه نمی‌کند. به‌جای آن، به خود React اجازه می‌دهد بر اساس وضعیت واقعی مرورگر و کارهای در صف، تصمیم بگیرد چه زمانی این به‌روزرسانی را کامل کند؛ و در این مدت، همچنان به رویدادهای فوری‌تر واکنش نشان دهد.

Transition، به دو چیز نیاز دارد تا معنا پیدا کند

برای این‌که مفهوم Transition عملی شود، به دو چیز نیاز است: یک راه برای علامت‌گذاری «این به‌روزرسانی خاص، انتقالی است» (که useTransition در درس بعدی فراهم می‌کند)، و یک راه برای نشان دادن این‌که در طول این گذار، چیزی هنوز در حال تکمیل شدن است، بدون قفل کردن کامل رابط کاربری (معمولاً با یک وضعیت pending یا یک افکت بصری ملایم، نه یک fallback کامل مثل Suspense).

ارتباط با Suspense که در فصل قبل دیدیم

در فصل بیست‌ویکم، در درس مربوط به رفتار Suspense در یک Update، اشاره کردیم که رفتار پیش‌فرض، پرش فوری به fallback است. Transition، دقیقاً ابزاری است که می‌تواند این پرش فوری را ملایم‌تر کند؛ یعنی اگر یک به‌روزرسانی، باعث Suspend شدن دوباره یک کامپوننت شود، علامت‌گذاری آن به‌عنوان Transition، به React اجازه می‌دهد محتوای قبلی را کمی بیشتر نگه دارد، به‌جای نمایش فوری fallback.

مثال قابل اجرا

در این مثال، هنوز از useTransition استفاده نشده (که موضوع درس بعدی است)؛ هدف فقط نشان دادن دوباره همان سناریویی است که Transition برای آن طراحی شده: تغییر محتوایی که سنگین است و می‌تواند فوریت کمتری نسبت به واکنش دکمه داشته باشد.

یک گذار (Transition) بین دو تب، بدون useTransition هنوز
import { useState } from "react";

function HeavyList({ label }) {
  const items = Array.from({ length: 8000 }, (_, i) => `${label} ${i}`);
  return (
    <ul>
      {items.slice(0, 15).map((item) => (
        <li key={item}>{item}</li>
      ))}
    </ul>
  );
}

function App() {
  const [tab, setTab] = useState("posts");

  return (
    <div>
      <button onClick={() => setTab("posts")}>پست‌ها</button>
      <button onClick={() => setTab("about")}>درباره</button>
      <HeavyList label={tab === "posts" ? "پست" : "اطلاعات"} />
    </div>
  );
}
برای دیدن پیش‌نمایش کامپوننت، روی Run بزنید.

جمع‌بندی

Transition، نام رسمی دسته‌ای از به‌روزرسانی‌هاست که نتیجه نهایی‌شان مهم است، اما لازم نیست بی‌وقفه و فوری کامل شوند؛ برخلاف Debounce/Throttle، هیچ تأخیر مصنوعی اضافه نمی‌کند و به‌جای آن، تصمیم زمان‌بندی را به خود React می‌سپارد. این مفهوم، با Suspense هم در ارتباط است و می‌تواند پرش فوری به fallback را ملایم‌تر کند. در درس بعدی، با useTransition، نحوه علامت‌گذاری عملی یک به‌روزرسانی به‌عنوان Transition را می‌بینیم.