مدیریت رویدادهای DOM و Window در React

مقدمه

در اپلیکیشن‌های React معمولاً لازم است به رویدادهای مختلفی که در DOM یا شیء window رخ می‌دهند واکنش نشان دهید. برای مثال ممکن است بخواهید:

  • هنگام تغییر اندازه پنجره مرورگر (Resize) کاری انجام دهید.
  • موقع اسکرول شدن صفحه اطلاعاتی را ثبت کنید.
  • فشرده شدن یک کلید خاص روی کیبورد را تشخیص دهید.
  • کلیک کاربر در خارج از یک المان را مدیریت کنید.

در React بهترین روش برای مدیریت این نوع رویدادها استفاده از Hookهایی مانند useEffect است تا بتوانید هنگام Mount شدن کامپوننت رویدادها را ثبت کرده و هنگام Unmount شدن آن‌ها را حذف کنید.

در این مقاله با نحوه مدیریت رویدادهای DOM و Window در React آشنا می‌شویم.


تفاوت رویدادهای React و رویدادهای DOM

در React معمولاً رویدادها را مستقیماً روی عناصر JSX تعریف می‌کنیم:

function Button() {
  return (
    <button onClick={() => console.log("Clicked!")}>
      Click Me
    </button>
  );
}

اما برخی رویدادها مستقیماً به عناصر JSX متصل نمی‌شوند و باید روی اشیایی مثل window یا document ثبت شوند.

برای مثال:

window.addEventListener("resize", handleResize);

در چنین شرایطی باید از useEffect استفاده کنیم.


مدیریت رویداد Resize پنجره

یکی از رایج‌ترین مثال‌ها، تشخیص تغییر اندازه پنجره مرورگر است.

مثال

import { useEffect, useState } from "react";

function WindowSize() {
  const [width, setWidth] = useState(window.innerWidth);

  useEffect(() => {
    function handleResize() {
      setWidth(window.innerWidth);
    }

    window.addEventListener("resize", handleResize);

    return () => {
      window.removeEventListener("resize", handleResize);
    };
  }, []);

  return <h2>Width: {width}px</h2>;
}

نحوه عملکرد

در این مثال:

  1. هنگام بارگذاری کامپوننت، Listener ثبت می‌شود.
  2. هر بار اندازه پنجره تغییر کند، مقدار State به‌روزرسانی می‌شود.
  3. هنگام حذف کامپوننت، Listener پاک می‌شود تا از نشت حافظه (Memory Leak) جلوگیری شود.

مدیریت رویداد Scroll

برای تشخیص اسکرول شدن صفحه می‌توانید از رویداد scroll استفاده کنید.

import { useEffect, useState } from "react";

function ScrollTracker() {
  const [scrollY, setScrollY] = useState(0);

  useEffect(() => {
    const handleScroll = () => {
      setScrollY(window.scrollY);
    };

    window.addEventListener("scroll", handleScroll);

    return () => {
      window.removeEventListener("scroll", handleScroll);
    };
  }, []);

  return <p>Scroll Position: {scrollY}px</p>;
}

در این مثال موقعیت فعلی اسکرول صفحه نمایش داده می‌شود.


مدیریت رویداد Keyboard

گاهی لازم است فشرده شدن کلیدهای صفحه‌کلید را تشخیص دهید.

import { useEffect } from "react";

function KeyboardListener() {
  useEffect(() => {
    const handleKeyDown = (event) => {
      console.log("Pressed:", event.key);
    };

    window.addEventListener("keydown", handleKeyDown);

    return () => {
      window.removeEventListener("keydown", handleKeyDown);
    };
  }, []);

  return <h2>Press any key</h2>;
}

تشخیص کلید خاص

مثلاً اگر بخواهید با فشردن کلید Escape یک مودال را ببندید:

useEffect(() => {
  const handleKeyDown = (event) => {
    if (event.key === "Escape") {
      closeModal();
    }
  };

  window.addEventListener("keydown", handleKeyDown);

  return () => {
    window.removeEventListener("keydown", handleKeyDown);
  };
}, []);

مدیریت کلیک خارج از یک عنصر

یکی از کاربردهای رایج React، بستن منو یا مودال هنگام کلیک خارج از آن است.

import { useEffect, useRef } from "react";

function Dropdown() {
  const menuRef = useRef();

  useEffect(() => {
    const handleClickOutside = (event) => {
      if (
        menuRef.current &&
        !menuRef.current.contains(event.target)
      ) {
        console.log("Clicked outside");
      }
    };

    document.addEventListener("mousedown", handleClickOutside);

    return () => {
      document.removeEventListener(
        "mousedown",
        handleClickOutside
      );
    };
  }, []);

  return (
    <div ref={menuRef}>
      Dropdown Content
    </div>
  );
}

در این مثال هر کلیکی که خارج از عنصر موردنظر انجام شود شناسایی خواهد شد.


استفاده از useEffect برای پاکسازی رویدادها

یکی از مهم‌ترین نکات هنگام کار با رویدادهای DOM، حذف Listenerها بعد از پایان استفاده است.

ساختار استاندارد:

useEffect(() => {
  window.addEventListener("resize", handleResize);

  return () => {
    window.removeEventListener(
      "resize",
      handleResize
    );
  };
}, []);

اگر Listener حذف نشود ممکن است:

  • مصرف حافظه افزایش پیدا کند.
  • چندین Listener تکراری ایجاد شود.
  • عملکرد برنامه کاهش یابد.

استفاده از Custom Hook

اگر چندین بار از یک رویداد استفاده می‌کنید، بهتر است یک Hook سفارشی بسازید.

مثال: Hook تشخیص اندازه پنجره

import { useEffect, useState } from "react";

function useWindowWidth() {
  const [width, setWidth] = useState(
    window.innerWidth
  );

  useEffect(() => {
    const handleResize = () => {
      setWidth(window.innerWidth);
    };

    window.addEventListener(
      "resize",
      handleResize
    );

    return () => {
      window.removeEventListener(
        "resize",
        handleResize
      );
    };
  }, []);

  return width;
}

استفاده:

function App() {
  const width = useWindowWidth();

  return <h1>{width}px</h1>;
}

نکات مهم

  • همیشه Listenerها را در useEffect ثبت کنید.
  • هنگام Unmount شدن کامپوننت، رویدادها را حذف کنید.
  • برای دسترسی به عناصر DOM از useRef استفاده کنید.
  • برای منطق‌های تکراری از Custom Hook کمک بگیرید.
  • از ثبت Listenerهای غیرضروری خودداری کنید تا عملکرد برنامه بهینه بماند.

جمع‌بندی

مدیریت رویدادهای DOM و Window در React بخش مهمی از توسعه رابط کاربری است. با استفاده از useEffect می‌توانید رویدادهایی مانند resize، scroll، keydown و click را به‌سادگی مدیریت کنید. همچنین با حذف Listenerها در زمان مناسب، از مشکلاتی مانند نشت حافظه و افت عملکرد جلوگیری خواهید کرد.

از همراهی شما با پارمین کلود سپاسگزاریم.

Click to rate this post!
[Total: 0 Average: 0]

نظرات کاربران

دیدگاهی بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *