فارسی

راهنمای جامع بررسی رف‌های ری‌اکت، با تمرکز بر useRef و createRef. بیاموزید چگونه و چه زمانی از هرکدام برای مدیریت بهینه کامپوننت و دسترسی به DOM در اپلیکیشن‌های جهانی استفاده کنید.

رف‌های (Refs) ری‌اکت: ابهام‌زدایی از useRef در مقابل createRef

در دنیای پویای توسعه ری‌اکت، مدیریت بهینه وضعیت (state) کامپوننت و تعامل با مدل شیء سند (DOM) بسیار حیاتی است. رف‌های ری‌اکت مکانیزمی برای دسترسی و دستکاری مستقیم عناصر DOM یا کامپوننت‌های ری‌اکت فراهم می‌کنند. دو روش اصلی برای ایجاد رف‌ها useRef و createRef هستند. در حالی که هر دو برای ایجاد رف‌ها به کار می‌روند، در پیاده‌سازی و موارد استفاده تفاوت دارند. هدف این راهنما ابهام‌زدایی از این دو رویکرد است تا مشخص شود چه زمانی و چگونه از هرکدام در پروژه‌های ری‌اکت خود، به‌ویژه هنگام توسعه برای مخاطبان جهانی، به طور مؤثر استفاده کنید.

درک رف‌های ری‌اکت

یک Ref (مخفف reference) قابلیتی در ری‌اکت است که به شما امکان می‌دهد مستقیماً به یک گره DOM یا یک کامپوننت ری‌اکت دسترسی داشته باشید. این قابلیت به‌ویژه در موارد زیر مفید است:

در حالی که ری‌اکت رویکردی اعلانی (declarative) را تشویق می‌کند، که در آن رابط کاربری از طریق state و props مدیریت می‌شود، موقعیت‌هایی وجود دارد که دستکاری مستقیم ضروری است. رف‌ها راهی برای پر کردن شکاف بین ماهیت اعلانی ری‌اکت و عملیات دستوری (imperative) روی DOM فراهم می‌کنند.

createRef: رویکرد کامپوننت‌های کلاسی

createRef متدی است که توسط ری‌اکت ارائه شده است. این متد عمدتاً در کامپوننت‌های کلاسی برای ایجاد رف‌ها استفاده می‌شود. هر بار که یک کامپوننت کلاسی نمونه‌سازی می‌شود، createRef یک شیء رف جدید ایجاد می‌کند. این تضمین می‌کند که هر نمونه از کامپوننت، رف منحصربه‌فرد خود را داشته باشد.

سینتکس و کاربرد

برای استفاده از createRef، ابتدا یک رف را در کامپوننت کلاسی خود، معمولاً در سازنده (constructor)، تعریف می‌کنید. سپس، رف را با استفاده از ویژگی ref به یک عنصر DOM یا یک کامپوننت متصل می‌کنید.


class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }

  componentDidMount() {
    // دسترسی به عنصر DOM پس از mount شدن کامپوننت
    this.myRef.current.focus();
  }

  render() {
    return ;
  }
}

در این مثال، this.myRef با استفاده از React.createRef() ایجاد می‌شود. سپس به ویژگی ref عنصر input اختصاص داده می‌شود. پس از اینکه کامپوننت mount شد (در componentDidMount)، می‌توانید با استفاده از this.myRef.current به گره واقعی DOM دسترسی پیدا کرده و عملیاتی روی آن انجام دهید (در این مورد، فوکوس کردن روی ورودی).

مثال: فوکوس کردن روی یک فیلد ورودی

سناریویی را در نظر بگیرید که می‌خواهید یک فیلد ورودی به طور خودکار هنگام mount شدن کامپوننت فوکوس شود. این یک مورد استفاده رایج برای رف‌ها است، به‌ویژه در فرم‌ها یا عناصر تعاملی.


class FocusInput extends React.Component {
  constructor(props) {
    super(props);
    this.inputRef = React.createRef();
  }

  componentDidMount() {
    this.inputRef.current.focus();
  }

  render() {
    return (
      
); } }

در این مثال، FocusInput بلافاصله پس از mount شدن، روی فیلد ورودی فوکوس می‌کند. این کار می‌تواند با هدایت توجه کاربر به عنصر ورودی به محض رندر شدن کامپوننت، تجربه کاربری را بهبود بخشد.

ملاحظات مهم در مورد createRef

useRef: هوک کامپوننت‌های تابعی

useRef یک هوک است که در ری‌اکت نسخه ۱۶.۸ معرفی شد. این هوک راهی برای ایجاد اشیاء رف قابل تغییر (mutable) در کامپوننت‌های تابعی فراهم می‌کند. برخلاف createRef، هوک useRef در هر بار رندر شدن کامپوننت، همان شیء رف را برمی‌گرداند. این ویژگی آن را برای نگهداری مقادیر بین رندرها بدون ایجاد رندر مجدد، ایده‌آل می‌سازد.

سینتکس و کاربرد

استفاده از useRef ساده است. شما هوک useRef را با ارسال یک مقدار اولیه فراخوانی می‌کنید. این هوک یک شیء با پراپرتی .current برمی‌گرداند که می‌توانید از آن برای دسترسی و تغییر مقدار استفاده کنید.


import React, { useRef, useEffect } from 'react';

function MyFunctionalComponent() {
  const myRef = useRef(null);

  useEffect(() => {
    // دسترسی به عنصر DOM پس از mount شدن کامپوننت
    if (myRef.current) {
      myRef.current.focus();
    }
  }, []);

  return ;
}

در این مثال، useRef(null) یک رف با مقدار اولیه null ایجاد می‌کند. هوک useEffect برای دسترسی به عنصر DOM پس از mount شدن کامپوننت استفاده می‌شود. پراپرتی myRef.current مرجع به عنصر input را نگه می‌دارد و به شما امکان می‌دهد روی آن فوکوس کنید.

مثال: ردیابی مقادیر قبلی prop

یکی از کاربردهای قدرتمند useRef، ردیابی مقدار قبلی یک prop است. از آنجایی که تغییرات در رف‌ها باعث رندر مجدد نمی‌شوند، می‌توانید از آنها برای ذخیره مقادیری که می‌خواهید در طول رندرها حفظ شوند بدون تأثیر بر رابط کاربری، استفاده کنید.


import React, { useRef, useEffect } from 'react';

function PreviousValueComponent({ value }) {
  const previousValue = useRef();

  useEffect(() => {
    previousValue.current = value;
  }, [value]);

  return (
    

مقدار فعلی: {value}

مقدار قبلی: {previousValue.current}

); }

در این مثال، previousValue.current مقدار قبلی prop با نام value را ذخیره می‌کند. هوک useEffect هر زمان که prop با نام value تغییر کند، رف را به‌روزرسانی می‌کند. این به شما امکان می‌دهد مقادیر فعلی و قبلی را مقایسه کنید، که می‌تواند برای تشخیص تغییرات یا پیاده‌سازی انیمیشن‌ها مفید باشد.

ملاحظات مهم در مورد useRef

useRef در مقابل createRef: مقایسه دقیق

اکنون که هر دو useRef و createRef را به صورت جداگانه بررسی کردیم، بیایید آنها را کنار هم مقایسه کنیم تا تفاوت‌های کلیدی آنها و زمان انتخاب یکی بر دیگری را برجسته کنیم.

ویژگی useRef createRef
نوع کامپوننت کامپوننت‌های تابعی کامپوننت‌های کلاسی
هوک یا متد هوک متد
نمونه رف در هر رندر همان شیء رف را برمی‌گرداند در هر نمونه از کامپوننت یک شیء رف جدید ایجاد می‌کند
موارد استفاده
  • دسترسی به عناصر DOM
  • حفظ مقادیر بین رندرها بدون ایجاد رندر مجدد
  • ردیابی مقادیر قبلی prop
  • ذخیره مقادیر قابل تغییری که باعث رندر مجدد نمی‌شوند
  • دسترسی به عناصر DOM
  • دسترسی به متدهای کامپوننت فرزند

انتخاب رف مناسب: راهنمای تصمیم‌گیری

در اینجا یک راهنمای ساده برای کمک به شما در انتخاب بین useRef و createRef آورده شده است:

فراتر از دستکاری DOM: موارد استفاده پیشرفته برای رف‌ها

در حالی که دسترسی و دستکاری عناصر DOM یک کاربرد اصلی برای رف‌ها است، آنها امکاناتی فراتر از این عملکرد اصلی ارائه می‌دهند. بیایید برخی از سناریوهای پیشرفته را که در آنها رف‌ها می‌توانند به‌ویژه مفید باشند، بررسی کنیم.

۱. دسترسی به متدهای کامپوننت فرزند

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


class ParentComponent extends React.Component {
  constructor(props) {
    super(props);
    this.childRef = React.createRef();
  }

  handleClick = () => {
    // فراخوانی یک متد در کامپوننت فرزند
    this.childRef.current.doSomething();
  };

  render() {
    return (
      
); } } class ChildComponent extends React.Component { doSomething = () => { console.log('اکشن کامپوننت فرزند اجرا شد!'); }; render() { return
این یک کامپوننت فرزند است.
; } }

در این مثال، ParentComponent از یک رف برای دسترسی به ChildComponent و فراخوانی متد doSomething آن استفاده می‌کند.

۲. مدیریت فوکوس و انتخاب

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


import React, { useRef, useEffect } from 'react';

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

  useEffect(() => {
    if (inputRef.current) {
      inputRef.current.focus();
      inputRef.current.select(); // انتخاب متن در ورودی
    }
  }, []);

  return ;
}

این مثال به محض mount شدن کامپوننت، روی ورودی فوکوس کرده و متن آن را انتخاب می‌کند.

۳. متحرک‌سازی عناصر

رف‌ها می‌توانند در ترکیب با کتابخانه‌های انیمیشن (مانند GreenSock یا Framer Motion) برای دستکاری مستقیم DOM و ایجاد انیمیشن‌های پیچیده استفاده شوند. این امکان کنترل دقیق بر توالی‌های انیمیشن را فراهم می‌کند.

مثال با استفاده از جاوا اسکریپت خالص برای سادگی:


import React, { useRef, useEffect } from 'react';

function AnimatedBox() {
  const boxRef = useRef(null);

  useEffect(() => {
    const box = boxRef.current;
    if (box) {
      // انیمیشن ساده: حرکت جعبه به سمت راست
      box.animate(
        [
          { transform: 'translateX(0)' },
          { transform: 'translateX(100px)' },
        ],
        {
          duration: 1000, // ۱ ثانیه
          iterations: Infinity, // تکرار بی نهایت
          direction: 'alternate',
        }
      );
    }
  }, []);

  return 
; }

این مثال از Web Animations API برای متحرک‌سازی یک جعبه ساده استفاده می‌کند و آن را به صورت افقی به عقب و جلو حرکت می‌دهد.

بهترین شیوه‌ها برای استفاده از رف‌های ری‌اکت در اپلیکیشن‌های جهانی

هنگام توسعه اپلیکیشن‌های ری‌اکت برای مخاطبان جهانی، مهم است که در نظر بگیرید چگونه رف‌ها با بین‌المللی‌سازی (i18n) و محلی‌سازی (l10n) تعامل دارند. در اینجا برخی از بهترین شیوه‌ها آورده شده است:

۱. دسترسی‌پذیری (A11y)

اطمینان حاصل کنید که استفاده شما از رف‌ها تأثیر منفی بر دسترسی‌پذیری نداشته باشد. به عنوان مثال، هنگام فوکوس کردن برنامه‌ریزی شده روی عناصر، ترتیب فوکوس کاربر را در نظر بگیرید و اینکه آیا تغییر فوکوس برای صفحه‌خوان‌ها و کاربران کیبورد مناسب است یا خیر.


import React, { useRef, useEffect } from 'react';

function AccessibleFocus() {
  const buttonRef = useRef(null);

  useEffect(() => {
    const button = buttonRef.current;
    if (button) {
      // فقط در صورتی فوکوس کنید که دکمه قبلاً توسط کاربر فوکوس نشده باشد
      if (document.activeElement !== button) {
        button.focus();
      }
    }
  }, []);

  return ;
}

۲. فیلدهای ورودی بین‌المللی

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

۳. طرح‌بندی‌های راست به چپ (RTL)

اگر اپلیکیشن شما از زبان‌های راست به چپ (مانند عربی، عبری) پشتیبانی می‌کند، اطمینان حاصل کنید که دستکاری‌های DOM شما با استفاده از رف‌ها، طرح‌بندی معکوس را در نظر می‌گیرند. به عنوان مثال، هنگام متحرک‌سازی عناصر، جهت انیمیشن را برای زبان‌های RTL معکوس کنید.

۴. ملاحظات عملکرد

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

نتیجه‌گیری

رف‌های ری‌اکت، به‌ویژه useRef و createRef، ابزارهای ضروری برای توسعه‌دهندگان ری‌اکت هستند. درک تفاوت‌های ظریف هر رویکرد و زمان استفاده مؤثر از آنها برای ساخت اپلیکیشن‌های قوی و کارآمد بسیار مهم است. createRef استاندارد مدیریت رف‌ها در کامپوننت‌های کلاسی باقی می‌ماند و تضمین می‌کند که هر نمونه، رف منحصربه‌فرد خود را دارد. useRef با ماهیت ماندگار خود در طول رندرها، برای کامپوننت‌های تابعی ایده‌آل است و راهی برای مدیریت عناصر DOM و حفظ مقادیر بدون ایجاد رندرهای غیرضروری ارائه می‌دهد. با استفاده هوشمندانه از این ابزارها، می‌توانید عملکرد و تجربه کاربری اپلیکیشن‌های ری‌اکت خود را بهبود بخشیده و با رابط‌های کاربری قابل دسترس و کارآمد، به مخاطبان جهانی خدمات ارائه دهید.

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