مقدمه
در درس قبل دیدیم که چگونه میتوان با برگرداندن یک تابع از داخل useEffect یک عملیات پاکسازی
را هنگام حذف شدن کامپوننت (unmount) اجرا کرد. این قابلیت تنها برای سادگی نیست، بلکه یک بخش حیاتی
برای جلوگیری از باگهای رایج و «نشت حافظه» (memory leak) در اپلیکیشنهای React است.
یک نشت حافظه زمانی اتفاق میافتد که برنامه منابعی (مانند حافظه یا listenerها) را رزرو میکند
اما پس از اتمام کار، آنها را به درستی آزاد نمیکند. این منابع اشغال شده به مرور زمان میتوانند
باعث کندی و در نهایت از کار افتادن اپلیکیشن شوند.
چه زمانی به پاکسازی نیاز داریم؟
هر افکتی که یک فرآیند یا اشتراک (subscription) مداوم را در پسزمینه راهاندازی میکند، باید یک
تابع پاکسازی داشته باشد.
مثال: اشتراک در یک سرویس چت
تصور کنید یک کامپوننت دارید که به یک سرویس چت متصل میشود تا پیامهای جدید را دریافت کند.
JAVASCRIPT (React)
import { useState, useEffect } from 'react';
import { createConnection } from './chat.js';
function ChatRoom({ roomId }) {
useEffect(() => {
const connection = createConnection(roomId);
connection.connect();
return () => {
connection.disconnect();
};
}, [roomId]);
return <h1>Welcome to the {roomId} room!</h1>;
}
در این کد، افکت ما یک اتصال به سرویس چت برقرار میکند. اگر کاربر از این اتاق چت خارج شود (و
کامپوننت ChatRoom از DOM حذف شود)، ما باید اتصال را قطع کنیم. تابع پاکسازی که disconnect
را فراخوانی میکند، دقیقاً این کار را انجام میدهد.
اگر این تابع پاکسازی وجود نداشت، اتصال به سرویس چت حتی پس از خروج کاربر از اتاق، در پسزمینه
فعال باقی میماند. این نه تنها منابع شبکه را هدر میدهد، بلکه میتواند منجر به دریافت پیامها
برای اتاقی شود که کاربر دیگر در آن حضور ندارد و باعث بروز باگهای عجیب شود.
چرخه اجرای افکت و پاکسازی
مهم است بدانید که React تابع پاکسازی را نه تنها هنگام unmount شدن کامل کامپوننت، بلکه قبل
از هر بار اجرای مجدد افکت نیز فراخوانی میکند.
چرا این رفتار مفید است؟
این رفتار تضمین میکند که هر افکت، محیط تمیزی برای شروع کار خود دارد. در مثال ChatRoom بالا،
اگر prop مربوط به roomId تغییر کند، React میخواهد یک افکت جدید برای اتصال به اتاق جدید
اجرا کند. اما قبل از آن، تابع پاکسازی افکت قبلی را اجرا میکند تا اتصال به
اتاق قدیمی قطع شود. این کار از ایجاد چندین اتصال همزمان و ناخواسته جلوگیری میکند.
Execution Flow
useEffect(() => {
connection = createConnection(roomId);
connection.connect();
return () => {
connection.disconnect();
};
}, [roomId]);
useEffect(() => {
connection = createConnection(roomId);
connection.connect();
return () => {
connection.disconnect();
};
}, [roomId]);
این ترتیب اجرای افکت و پاکسازی به ما اطمینان میدهد که همیشه فقط یک اتصال فعال به اتاق چت
وجود دارد و منابع به درستی مدیریت میشوند.
در این درس، با اهمیت حیاتی تابع پاکسازی در هوک useEffect آشنا شدیم. دیدیم که این تابع نه تنها
برای جلوگیری از نشت حافظه هنگام unmount شدن کامپوننت ضروری است، بلکه با اجرا شدن قبل از هر
افکت جدید، به ما کمک میکند تا عوارض جانبی خود را به صورت تمیز و قابل پیشبینی مدیریت کنیم.
با این درس، فصل «افکتها و چرخه حیات کامپوننت» به پایان میرسد. شما اکنون دو هوک اصلی و بنیادی
React، یعنی useState و useEffect را به خوبی میشناسید و میتوانید کامپوننتهای تعاملی و
پویا بسازید که با دنیای خارج نیز در تعامل هستند. در فصل بعدی، «توانمندسازی اپهای وب با هوکها»،
با هوکهای دیگر و الگوهای پیشرفتهتری مانند ساخت هوکهای سفارشی آشنا خواهیم شد.