چرخه اجرای Effect: Mount، Update و Unmount

در درس‌های قبلی این فصل، تک‌تک بخش‌های یک Effect (بدنه اصلی، Dependency Array، Cleanup) را جداگانه بررسی کردیم. در این درس، همه این بخش‌ها را کنار هم می‌گذاریم تا ببینیم دقیقاً در سه مرحله اصلی زندگی یک کامپوننت، یعنی Mount، Update و Unmount، یک Effect چه رفتاری از خود نشان می‌دهد.

یادآوری سه مفهوم پایه

پیش از ادامه، سه اصطلاح این درس را مرور می‌کنیم:

  • Mount: لحظه‌ای که یک کامپوننت برای اولین بار در صفحه ظاهر می‌شود.
  • Update (یا Re-render): رندر مجدد کامپوننتی که از قبل روی صفحه بوده، معمولاً به‌دلیل تغییر State یا Props.
  • Unmount: لحظه‌ای که کامپوننت به‌طور کامل از صفحه حذف می‌شود.

بررسی دقیق‌تر و رسمی‌تر این مفاهیم، موضوع فصل یازدهم (مدل رندرینگ React) است؛ در این‌جا فقط به‌اندازه‌ای که برای فهم چرخه Effect لازم است، به آن‌ها می‌پردازیم.

Effectی با Dependency Array خالی

useEffect(() => {
  console.log("اجرای Effect");
  return () => console.log("اجرای Cleanup");
}, []);

برای این Effect، چرخه اجرا به این شکل است:

  • هنگام Mount: فقط بدنه اصلی Effect اجرا می‌شود («اجرای Effect»).
  • در هر Update: چون Dependency Array خالی است، هیچ مقداری تغییر نکرده؛ پس نه Cleanup و نه بدنه اصلی، هیچ‌کدام دوباره اجرا نمی‌شوند.
  • هنگام Unmount: فقط تابع Cleanup اجرا می‌شود («اجرای Cleanup»).

Effectی با یک یا چند Dependency

useEffect(() => {
  console.log("اتصال به اتاق", roomId);
  return () => console.log("قطع اتصال از اتاق", roomId);
}, [roomId]);

برای این Effect، فرض کنید کامپوننت با roomId="۱" نمایش داده می‌شود و سپس به roomId="۲" تغییر می‌کند و در نهایت از صفحه حذف می‌شود. ترتیب کامل اجرا به این شکل است:

۱. Mount با roomId=۱      → "اتصال به اتاق ۱"
۲. Update با roomId=۲     → "قطع اتصال از اتاق ۱"
                            → "اتصال به اتاق ۲"
۳. Unmount                → "قطع اتصال از اتاق ۲"

نکته مهم در مرحله دوم این است که پیش از اجرای بدنه جدید Effect (برای roomId=۲)، ابتدا Cleanup مربوط به اجرای قبلی (برای roomId=۱) فراخوانی می‌شود؛ دقیقاً همان رفتاری که در درس Cleanup دیدیم.

Effectی بدون Dependency Array

اگر آرگومان دوم اصلاً داده نشود، Effect پس از هر رندر، چه هنگام Mount و چه هر Update، دوباره اجرا می‌شود؛ و پیش از هر اجرای دوباره (به‌جز اولین بار)، Cleanup اجرای قبلی هم فراخوانی می‌شود. همان‌طور که در درس اول این فصل اشاره شد، این حالت به‌ندرت مورد نیاز واقعی است.

یک نکته مهم درباره محیط توسعه (فقط جنبه آموزشی)

در حالت توسعه (Development Mode)، React ممکن است برای کمک به تشخیص Effectهایی که Cleanup درستی ندارند، هنگام Mount یک‌بار Effect را اجرا کند، بلافاصله Cleanup آن را فراخوانی کند، و سپس دوباره Effect را اجرا کند. این رفتار فقط در حالت توسعه است و در نسخه نهایی (Production) رخ نمی‌دهد؛ هدف از آن، آشکار کردن Effectهایی است که بدون Cleanup مناسب نوشته شده‌اند.

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

مشاهده ترتیب اجرای Effect و Cleanup
برای دیدن پیش‌نمایش کامپوننت، روی Run بزنید.

جمع‌بندی

در طول عمر یک کامپوننت، یک Effect با Dependency مشخص، هنگام Mount فقط بدنه اصلی را اجرا می‌کند، در هر Update که Dependency تغییر کرده باشد ابتدا Cleanup قبلی و سپس بدنه جدید را اجرا می‌کند، و هنگام Unmount فقط Cleanup نهایی را اجرا می‌کند. در درس بعدی به دو مشکل رایج مرتبط با همین چرخه اجرا می‌پردازیم: Race Condition و Stale Closure.