استفاده از Ref برای دسترسی مستقیم به عناصر DOM

در درس قبلی با مفهوم پایه useRef به‌عنوان نگهدارنده یک مقدار Mutable آشنا شدیم. یکی از رایج‌ترین و مهم‌ترین کاربردهای Ref، اتصال مستقیم آن به یک عنصر واقعی DOM است؛ کاری که در درس‌های قبلی، برای Uncontrolled Components هم از آن استفاده کرده بودیم. در این درس، این کاربرد را با جزئیات کامل بررسی می‌کنیم.

مشکل: React معمولاً دسترسی مستقیم به DOM را پنهان می‌کند

همان‌طور که در فصل اول دیدیم، در مدل ذهنی React، ما رابط کاربری را توصیف می‌کنیم و React خودش تصمیم می‌گیرد چه تغییری در DOM واقعی لازم است. اما گاهی نیاز داریم مستقیماً به یک عنصر DOM دسترسی داشته باشیم؛ مثلاً برای قرار دادن فوکوس روی یک input، اندازه‌گیری ابعاد یک عنصر، یا پخش یک ویدیو.

اتصال Ref به یک عنصر JSX

برای این کار، یک Ref با useRef(null) می‌سازیم و آن را به ویژگی ref روی عنصر موردنظر می‌دهیم. React به‌طور خودکار، پس از قرار گرفتن آن عنصر در DOM، مقدار current را برابر با همان عنصر واقعی تنظیم می‌کند:

function SearchBox() {
  const inputRef = useRef(null);

  function handleFocusClick() {
    inputRef.current.focus();
  }

  return (
    <div>
      <input ref={inputRef} />
      <button onClick={handleFocusClick}>فوکوس روی فیلد</button>
    </div>
  );
}

در این مثال، با کلیک روی دکمه، متد focus() که یک متد استاندارد عناصر DOM است (نه چیزی مخصوص React)، مستقیماً روی همان عنصر input فراخوانی می‌شود.

مقدار Ref پیش از Mount برابر null است

نکته مهمی که باید در نظر داشت این است که پیش از این‌که کامپوننت رندر و در DOM قرار گیرد، مقدار inputRef.current برابر null است. به همین دلیل، تلاش برای دسترسی به آن در طول محاسبه JSX (یعنی در حین رندر)، به یک مقدار معتبر نمی‌رسد. React مقدار current را فقط پس از Commit شدن تغییرات در DOM واقعی، تنظیم می‌کند؛ به همین دلیل، خواندن آن باید داخل Event Handler یا Effect انجام شود، نه در بدنه اصلی کامپوننت.

یک کاربرد رایج: فوکوس خودکار هنگام Mount

ترکیب Ref با useEffect، یکی از الگوهای رایج برای انجام کاری روی یک عنصر DOM، بلافاصله پس از قرار گرفتنش در صفحه است:

function SearchBox() {
  const inputRef = useRef(null);

  useEffect(() => {
    inputRef.current.focus();
  }, []);

  return <input ref={inputRef} />;
}

در این کد، چون Effect پس از Commit شدن DOM اجرا می‌شود، در آن لحظه inputRef.current دیگر null نیست و به‌درستی به عنصر واقعی input اشاره می‌کند.

Ref روی DOM را فقط برای کارهایی استفاده کنید که React انجامش نمی‌دهد

استفاده از Ref برای تغییر مستقیم محتوای یک عنصر (مثلاً با textContent) در حالی که همان عنصر توسط State هم کنترل می‌شود، می‌تواند باعث ناهماهنگی بین آنچه React فکر می‌کند در DOM هست و آنچه واقعاً در DOM وجود دارد شود. قاعده کلی این است: از Ref برای کارهایی مانند فوکوس، اسکرول، اندازه‌گیری یا پخش رسانه استفاده کنید؛ نه برای تغییر محتوایی که React خودش مسئول رندر آن است.

مثال قابل اجرا

فوکوس خودکار روی input هنگام Mount
برای دیدن پیش‌نمایش کامپوننت، روی Run بزنید.

جمع‌بندی

با دادن یک Ref به ویژگی ref یک عنصر JSX، React پس از Commit شدن DOM، مقدار current را برابر همان عنصر واقعی تنظیم می‌کند؛ این امکان دسترسی مستقیم برای کارهایی مانند فوکوس یا اندازه‌گیری را فراهم می‌کند. پیش از Mount، این مقدار همیشه null است، پس خواندن آن باید داخل Event Handler یا Effect انجام شود. در درس بعدی، Ref را در برابر State مقایسه می‌کنیم تا تفاوت کاربردشان روشن‌تر شود.