مقدمه
در درس قبل دیدیم که چگونه میتوان با استفاده از آرایه وابستگیها، اجرای افکتها را کنترل کرد. دو
مورد از رایجترین سناریوها برای عوارض جانبی، اجرای یک عملیات دقیقاً یک بار، زمانی که کامپوننت
برای اولین بار به DOM اضافه میشود (که به آن mounting میگویند)، و اجرای یک عملیات پاکسازی،
درست قبل از اینکه کامپوننت از DOM حذف شود (که به آن unmounting میگویند) است.
هوک useEffect به ما اجازه میدهد تا هر دوی این رفتارها را که در کامپوننتهای کلاسمحور با
متدهای چرخه حیات componentDidMount و componentWillUnmount انجام میشدند، به صورت ساده و
اعلانی پیادهسازی کنیم.
اجرای افکت فقط در زمان Mount
همانطور که در درس قبل اشاره شد، برای اینکه یک افکت تنها یک بار پس از رندر اولیه کامپوننت اجرا
شود، کافیست یک آرایه خالی را به عنوان آرایه وابستگیها به useEffect پاس دهیم.
کاربرد: دریافت دادههای اولیه
این الگو برای دریافت دادههای اولیه از یک API بسیار رایج است. شما میخواهید دادهها را تنها یک
بار هنگام بارگذاری کامپوننت دریافت کنید و دیگر نیازی به درخواست مجدد در رندرهای بعدی ندارید.
JAVASCRIPT (React)
import { useState, useEffect } from 'react';
function PostList() {
const [posts, setPosts] = useState([]);
useEffect(() => {
console.log('Component mounted, fetching data...');
fetch('https://api.example.com/posts')
.then(response => response.json())
.then(data => setPosts(data));
}, []);
return (
<ul>
{posts.map(post => <li key={post.id}>{post.title}</li>)}
</ul>
);
}
در این مثال، پیام "Component mounted, fetching data..." تنها یک بار در کنسول چاپ خواهد شد، صرف
نظر از اینکه کامپوننت PostList چند بار ممکن است به دلایل دیگر دوباره رندر شود. این کار از
ارسال درخواستهای شبکه غیرضروری و مکرر جلوگیری میکند.
اجرای کد پاکسازی هنگام Unmount
بسیاری از عوارض جانبی نیاز به یک مرحله «پاکسازی» (cleanup) دارند. برای مثال، اگر شما یک
subscription به یک سرویس خارجی (مانند یک WebSocket) ایجاد کردهاید یا یک تایمر با
setInterval تنظیم کردهاید، باید هنگام حذف کامپوننت از DOM، آن subscription را لغو یا آن
تایمر را پاک کنید تا از نشت حافظه (memory leak) و باگهای غیرمنتظره جلوگیری شود.
برگرداندن یک تابع پاکسازی
برای پیادهسازی این منطق، کافیست از تابع افکت خود، یک تابع دیگر را برگردانید. این تابع بازگشتی،
تابع پاکسازی شماست. React این تابع پاکسازی را درست قبل از اینکه کامپوننت از DOM حذف شود
(unmount)، اجرا خواهد کرد.
JAVASCRIPT (React)
import { useState, useEffect } from 'react';
function Timer() {
const [time, setTime] = useState(0);
useEffect(() => {
const timerId = setInterval(() => {
setTime(t => t + 1);
}, 1000);
console.log('Timer started!');
return () => {
clearInterval(timerId);
console.log('Timer cleaned up!');
};
}, []);
return <p>Time: {time}</p>;
}
در این مثال، افکت ما یک تایمر را با setInterval راهاندازی میکند. ما یک تابع پاکسازی را
برمیگردانیم که clearInterval را فراخوانی میکند.
وقتی کامپوننت Timer برای اولین بار رندر میشود، افکت اجرا شده و تایمر شروع به کار میکند. اگر
این کامپوننت بعداً از UI حذف شود (مثلاً کاربر به صفحه دیگری برود)، React قبل از حذف آن از
DOM، تابع پاکسازی را اجرا کرده و تایمر را متوقف میکند. این کار تضمین میکند که تایمر در
پسزمینه به صورت بیهوده به کار خود ادامه ندهد.
در این درس، با نحوه شبیهسازی متدهای چرخه حیات componentDidMount و componentWillUnmount با
استفاده از هوک useEffect آشنا شدیم. دیدیم که چگونه میتوان با یک آرایه وابستگی خالی افکتها را
تنها یک بار اجرا کرد و چگونه با برگرداندن یک تابع پاکسازی، از نشت حافظه جلوگیری نمود. در درس
بعدی، به «پاکسازی منابع و جلوگیری از memory leak» با جزئیات بیشتری خواهیم پرداخت و سناریوهای
پیچیدهتر پاکسازی را بررسی خواهیم کرد.