مقدمه

در درس قبل دیدیم که چگونه می‌توان با برگرداندن یک تابع از داخل useEffect یک عملیات پاک‌سازی را هنگام حذف شدن کامپوننت (unmount) اجرا کرد. این قابلیت تنها برای سادگی نیست، بلکه یک بخش حیاتی برای جلوگیری از باگ‌های رایج و «نشت حافظه» (memory leak) در اپلیکیشن‌های React است.

یک نشت حافظه زمانی اتفاق می‌افتد که برنامه منابعی (مانند حافظه یا listenerها) را رزرو می‌کند اما پس از اتمام کار، آنها را به درستی آزاد نمی‌کند. این منابع اشغال شده به مرور زمان می‌توانند باعث کندی و در نهایت از کار افتادن اپلیکیشن شوند.

چه زمانی به پاک‌سازی نیاز داریم؟

هر افکتی که یک فرآیند یا اشتراک (subscription) مداوم را در پس‌زمینه راه‌اندازی می‌کند، باید یک تابع پاک‌سازی داشته باشد.

مثال: اشتراک در یک سرویس چت

تصور کنید یک کامپوننت دارید که به یک سرویس چت متصل می‌شود تا پیام‌های جدید را دریافت کند.

Copy Icon JAVASCRIPT (React)
import { useState, useEffect } from 'react';
import { createConnection } from './chat.js';

function ChatRoom({ roomId }) {
  useEffect(() => {
    const connection = createConnection(roomId);
    connection.connect();
    
    // The cleanup function
    return () => {
      connection.disconnect();
    };
  }, [roomId]);

  return <h1>Welcome to the {roomId} room!</h1>;
}

در این کد، افکت ما یک اتصال به سرویس چت برقرار می‌کند. اگر کاربر از این اتاق چت خارج شود (و کامپوننت ChatRoom از DOM حذف شود)، ما باید اتصال را قطع کنیم. تابع پاک‌سازی که disconnect را فراخوانی می‌کند، دقیقاً این کار را انجام می‌دهد.

اگر این تابع پاک‌سازی وجود نداشت، اتصال به سرویس چت حتی پس از خروج کاربر از اتاق، در پس‌زمینه فعال باقی می‌ماند. این نه تنها منابع شبکه را هدر می‌دهد، بلکه می‌تواند منجر به دریافت پیام‌ها برای اتاقی شود که کاربر دیگر در آن حضور ندارد و باعث بروز باگ‌های عجیب شود.

چرخه اجرای افکت و پاک‌سازی

مهم است بدانید که React تابع پاک‌سازی را نه تنها هنگام unmount شدن کامل کامپوننت، بلکه قبل از هر بار اجرای مجدد افکت نیز فراخوانی می‌کند.

چرا این رفتار مفید است؟

این رفتار تضمین می‌کند که هر افکت، محیط تمیزی برای شروع کار خود دارد. در مثال ChatRoom بالا، اگر prop مربوط به roomId تغییر کند، React می‌خواهد یک افکت جدید برای اتصال به اتاق جدید اجرا کند. اما قبل از آن، تابع پاک‌سازی افکت قبلی را اجرا می‌کند تا اتصال به اتاق قدیمی قطع شود. این کار از ایجاد چندین اتصال همزمان و ناخواسته جلوگیری می‌کند.

Copy Icon Execution Flow
// 1. component mount
useEffect(() => {
  // 2. effect runs
    connection = createConnection(roomId);
    connection.connect();
    // 3. cleanup function is registered
    return () => {
      // 4. cleanup before new effect runs
      connection.disconnect();
    };
}, [roomId]);
// 5. if roomId changes
useEffect(() => {
  // 6. new effect runs
  connection = createConnection(roomId);
  connection.connect();
  // 7. cleanup function is registered
  return () => {
    // 8. cleanup before new effect runs
    connection.disconnect();
  };
}, [roomId]);

این ترتیب اجرای افکت و پاک‌سازی به ما اطمینان می‌دهد که همیشه فقط یک اتصال فعال به اتاق چت وجود دارد و منابع به درستی مدیریت می‌شوند.

در این درس، با اهمیت حیاتی تابع پاک‌سازی در هوک useEffect آشنا شدیم. دیدیم که این تابع نه تنها برای جلوگیری از نشت حافظه هنگام unmount شدن کامپوننت ضروری است، بلکه با اجرا شدن قبل از هر افکت جدید، به ما کمک می‌کند تا عوارض جانبی خود را به صورت تمیز و قابل پیش‌بینی مدیریت کنیم.

با این درس، فصل «افکت‌ها و چرخه حیات کامپوننت» به پایان می‌رسد. شما اکنون دو هوک اصلی و بنیادی React، یعنی useState و useEffect را به خوبی می‌شناسید و می‌توانید کامپوننت‌های تعاملی و پویا بسازید که با دنیای خارج نیز در تعامل هستند. در فصل بعدی، «توانمندسازی اپ‌های وب با هوک‌ها»، با هوک‌های دیگر و الگوهای پیشرفته‌تری مانند ساخت هوک‌های سفارشی آشنا خواهیم شد.