مقدمه

در درس قبل دیدیم که چگونه می‌توان با استفاده از آرایه وابستگی‌ها، اجرای افکت‌ها را کنترل کرد. دو مورد از رایج‌ترین سناریوها برای عوارض جانبی، اجرای یک عملیات دقیقاً یک بار، زمانی که کامپوننت برای اولین بار به DOM اضافه می‌شود (که به آن mounting می‌گویند)، و اجرای یک عملیات پاک‌سازی، درست قبل از اینکه کامپوننت از DOM حذف شود (که به آن unmounting می‌گویند) است.

هوک useEffect به ما اجازه می‌دهد تا هر دوی این رفتارها را که در کامپوننت‌های کلاس‌محور با متدهای چرخه حیات componentDidMount و componentWillUnmount انجام می‌شدند، به صورت ساده و اعلانی پیاده‌سازی کنیم.

اجرای افکت فقط در زمان Mount

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

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

این الگو برای دریافت داده‌های اولیه از یک API بسیار رایج است. شما می‌خواهید داده‌ها را تنها یک بار هنگام بارگذاری کامپوننت دریافت کنید و دیگر نیازی به درخواست مجدد در رندرهای بعدی ندارید.

Copy Icon 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));
  }, []); // <-- Empty array means this effect runs only once

  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)، اجرا خواهد کرد.

Copy Icon JAVASCRIPT (React)
import { useState, useEffect } from 'react';

function Timer() {
  const [time, setTime] = useState(0);

  useEffect(() => {
    // Set up the timer
    const timerId = setInterval(() => {
      setTime(t => t + 1);
    }, 1000);

    console.log('Timer started!');

    // Return the cleanup function
    return () => {
      clearInterval(timerId);
      console.log('Timer cleaned up!');
    };
  }, []); // Run once on mount, cleanup on unmount

  return <p>Time: {time}</p>;
}

در این مثال، افکت ما یک تایمر را با setInterval راه‌اندازی می‌کند. ما یک تابع پاک‌سازی را برمی‌گردانیم که clearInterval را فراخوانی می‌کند.

وقتی کامپوننت Timer برای اولین بار رندر می‌شود، افکت اجرا شده و تایمر شروع به کار می‌کند. اگر این کامپوننت بعداً از UI حذف شود (مثلاً کاربر به صفحه دیگری برود)، React قبل از حذف آن از DOM، تابع پاک‌سازی را اجرا کرده و تایمر را متوقف می‌کند. این کار تضمین می‌کند که تایمر در پس‌زمینه به صورت بیهوده به کار خود ادامه ندهد.

در این درس، با نحوه شبیه‌سازی متدهای چرخه حیات componentDidMount و componentWillUnmount با استفاده از هوک useEffect آشنا شدیم. دیدیم که چگونه می‌توان با یک آرایه وابستگی خالی افکت‌ها را تنها یک بار اجرا کرد و چگونه با برگرداندن یک تابع پاک‌سازی، از نشت حافظه جلوگیری نمود. در درس بعدی، به «پاک‌سازی منابع و جلوگیری از memory leak» با جزئیات بیشتری خواهیم پرداخت و سناریوهای پیچیده‌تر پاک‌سازی را بررسی خواهیم کرد.