کاربردهای مدرن Suspense

در درس‌های قبل این فصل، Suspense را تقریباً فقط در کنار lazy دیدیم. اما همان‌طور که چند بار اشاره کردیم، این مکانیزم، مفهومی عمومی‌تر از فقط بارگذاری کد است. در این درس، نمایی کلی از کاربردهای دیگر Suspense در React مدرن می‌دهیم؛ بدون ورود به جزئیات کامل پیاده‌سازی هرکدام، که در فصل‌های بعدی این دوره دنبال می‌شوند.

یادآوری اصل کلی

در درس اول این فصل گفتیم: Suspense، مرزی است که منتظر می‌ماند تا فرزندانش اعلام کنند آماده Render شدن هستند. lazy، فقط یکی از راه‌هایی است که یک کامپوننت می‌تواند این «هنوز آماده نیستم» را اعلام کند. React مدرن، چند راه دیگر هم برای همین اعلام فراهم کرده است.

کاربرد اول: Suspense برای دریافت داده

در فصل چهاردهم، الگوی دستی Loading/Error را برای دریافت داده ساختیم. در مدل مبتنی‌بر Suspense، به‌جای نگه‌داشتن یک State جداگانه برای loading، خود عملیات خواندن داده، اگر هنوز آماده نباشد، کامپوننت را Suspend می‌کند و نزدیک‌ترین Suspense، به‌طور خودکار fallback را نشان می‌دهد. این الگو، به زیرساخت خاصی نیاز دارد (یک منبع داده که از Suspense پشتیبانی کند)، که در فصل چهاردهم و شانزدهم، هنگام معرفی کتابخانه‌های تخصصی Server State، به آن اشاره کردیم؛ این کتابخانه‌ها، معمولاً از همین مکانیزم استفاده می‌کنند.

کاربرد دوم: use، یک Hook جدید برای خواندن Promise

React یک Hook به نام use معرفی کرده که اجازه می‌دهد مستقیم یک Promise را در بدنه کامپوننت بخوانیم؛ اگر آن Promise هنوز حل نشده باشد، use خودش کامپوننت را Suspend می‌کند:

jsx
function ProfileName({ userPromise }) {
  const user = use(userPromise);
  return <p>{user.name}</p>;
}

این Hook، با جزئیات کامل، در فصل بیست‌وسوم همین دوره بررسی می‌شود؛ اینجا فقط به‌عنوان نمونه‌ای از این‌که «راه‌های دیگری غیر از lazy برای Suspend کردن وجود دارد» اشاره شد.

کاربرد سوم: Server Components و Streaming

در معماری‌های مبتنی‌بر Server Components (که در فصل بیست‌وچهارم بررسی می‌شود)، Suspense نقش مهم‌تری پیدا می‌کند: بخش‌های مختلف یک صفحه، می‌توانند از سرور، به‌تدریج و جداگانه (Streaming) به مرورگر برسند، و هر مرز Suspense، مشخص می‌کند کدام بخش، مستقل از بقیه، می‌تواند زودتر یا دیرتر ظاهر شود. این یعنی همان الگوی «چند Suspense مستقل» که در درس‌های قبل دیدیم، در این معماری، به سطح کل یک صفحه گسترش پیدا می‌کند.

کاربرد چهارم: هماهنگی با useTransition

همان‌طور که در درس دوم این فصل اشاره کردیم، وقتی یک کامپوننت از قبل Render شده، به‌خاطر یک Update دوباره Suspend می‌شود، useTransition اجازه می‌دهد محتوای قبلی، به‌جای پرش فوری به fallback، کمی بیشتر نگه داشته شود. این ترکیب، موضوع کامل فصل بعدی این دوره، درباره Concurrent Rendering، خواهد بود.

چرا این نمای کلی، بدون جزئیات کامل، کافی است

هدف این درس، نشان دادن این بود که Suspense، یک مکانیزم زیربنایی است که در چند نقطه مختلف React مدرن (دریافت داده، use، Server Components، Concurrent Rendering) دوباره ظاهر می‌شود؛ نه این‌که هرکدام از این موارد را کامل یاد بگیریم. با این پایه، فصل‌های بعدی این دوره، وقتی دوباره به Suspense برخورد کنید، آشنا و قابل‌درک خواهند بود.

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

در این مثال، همان مفهوم اصلی (Suspense به‌عنوان یک مرز عمومی برای «ناآماده بودن») را، این‌بار با یک Promise دستی به‌جای lazy، شبیه‌سازی می‌کنیم؛ نزدیک به چیزی که Hook جدید use در پشت صحنه انجام می‌دهد.

شبیه‌سازی Suspend شدن از طریق یک Promise دستی
import { Suspense } from "react";

function createResource(promise) {
  let status = "pending";
  let result;
  const suspender = promise.then(
    (data) => {
      status = "success";
      result = data;
    },
    (error) => {
      status = "error";
      result = error;
    }
  );

  return {
    read() {
      if (status === "pending") throw suspender;
      if (status === "error") throw result;
      return result;
    },
  };
}

const userResource = createResource(
  new Promise((resolve) => setTimeout(() => resolve({ name: "سارا" }), 1000))
);

function ProfileName() {
  const user = userResource.read();
  return <p>نام: {user.name}</p>;
}

function App() {
  return (
    <Suspense fallback={<p>در حال بارگذاری نام کاربر...</p>}>
      <ProfileName />
    </Suspense>
  );
}
برای دیدن پیش‌نمایش کامپوننت، روی Run بزنید.

جمع‌بندی

Suspense، فراتر از lazy، در چند الگوی مدرن دیگر هم ظاهر می‌شود: دریافت داده مبتنی‌بر Suspense، Hook جدید use برای خواندن Promise، Streaming در Server Components، و هماهنگی با useTransition برای Updateهای نرم‌تر. این موارد، با جزئیات کامل، در فصل‌های آینده همین دوره بررسی می‌شوند. در درس بعدی، به محدودیت‌ها و مدل ذهنی نهایی Suspense می‌پردازیم.