🚀 إتقان useRef: جسرك للوصول إلى عناصر الصفحة في React

حتى الآن، تعلمت أن React تدير الواجهة بناءً على "الحالة" (State)، وعندما تتغير الحالة، يقوم React بتحديث الصفحة تلقائياً.

لكن، هل هناك حالات نحتاج فيها إلى "لمس" عنصر HTML مباشرة؟ أو تخزين قيمة معينة دون أن تتسبب في إعادة تشغيل الرندر (Re-render) للمكون؟ هنا يأتي دور الـ Hook السحري الذي يسمى useRef.


❓ ما هو الـ useRef ببساطة؟

الـ useRef هو عبارة عن "صندوق" أو "مرجع" يمكنك وضع أي قيمة داخله، وهذه القيمة تبقى ثابتة ومحفوظة طوال فترة حياة المكون.

هناك فائدتان أساسيتان لاستخدامه:

  1. الوصول المباشر لعناصر DOM: مثل التركيز على حقل إدخال (Input Focus)، أو معرفة عرض عنصر معين.
  2. تخزين قيم متغيرة لا تؤثر على الواجهة: إذا قمت بتغيير قيمة داخل useRef فإن React لن تعيد بناء المكون (No Re-render)، وهذا يختلف تماماً عن useState.

🛠️ كيف نستخدم useRef للوصول إلى عناصر HTML؟

تخيل أنك تريد جعل مؤشر الكتابة يظهر تلقائياً في حقل الإدخال (Input) بمجرد الضغط على زر معين. في JavaScript العادية كنت ستستخدم document.getElementById(). أما في React، فالطريقة الاحترافية هي استخدام useRef.

إليك الخطوات بالتفصيل:

  1. استيراد useRef من مكتبة React.
  2. إنشاء مرجع (Ref) باستخدام useRef(null).
  3. ربط هذا المرجع بالعنصر المطلوب عن طريق خاصية ref.
  4. الوصول للعنصر عبر الخاصية .current.

لنطبق ذلك في هذا المثال البسيط:

import React, { useRef } from 'react';

function TextInputFocus() {
  // 1. Create a ref initialized to null
  const inputElement = useRef(null);

  const handleFocusClick = () => {
    // 3. Access the DOM element using .current and call focus()
    // الوصول إلى العنصر الحقيقي في الصفحة وتنفيذ أمر التركيز
    inputElement.current.focus();
  };

  return (
    <div style={{ padding: '20px' }}>
      {/* 2. Attach the ref to the input element */}
      <input 
        ref={inputElement} 
        type="text" 
        placeholder="Click the button to focus me!" 
      />
      <br /><br />
      <button onClick={handleFocusClick}>
        Focus the Input 🎯
      </button>
    </div>
  );
}

export default TextInputFocus;

شرح الكود:

  • useRef(null): أنشأنا حاوية فارغة في البداية.
  • ref={inputElement}: أخبرنا React "يا ريأكت، اربطي هذا المدخل (Input) بهذا المرجع".
  • inputElement.current: هنا تكمن القوة، فكلمة current هي التي تحتوي على عنصر الـ HTML الفعلي.

📦 استخدام useRef لتخزين قيم (بدون Re-render)

أحياناً نحتاج لتخزين قيمة ما (مثل مؤقت أو رقم معين)، ولكننا لا نريد أن تظهر هذه القيمة في الواجهة، ولا نريد أن يتم تحديث الصفحة كلما تغيرت هذه القيمة.

قارن بين useState و useRef:

  • useState: عندما تتغير القيمة ⬅️ يعيد React تشغيل المكون ⬅️ تتحدث الواجهة (UI).
  • useRef: عندما تتغير القيمة ⬅️ لا يعيد React تشغيل المكون ⬅️ لا تتحدث الواجهة.

مثال توضيحي:

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

function ClickCounter() {
  const [renderCount, setRenderCount] = useState(0); // State causes re-render
  const countRef = useRef(0); // Ref does NOT cause re-render

  const incrementRef = () => {
    countRef.current = countRef.current + 1;
    console.log("Ref Value:", countRef.current); 
    // القيمة تزيد في الخلفية لكن الصفحة لا تتحدث
  };

  const incrementState = () => {
    setRenderCount(renderCount + 1);
    // هنا الصفحة ستعيد بناء نفسها وتظهر القيمة الجديدة
  };

  return (
    <div style={{ padding: '20px' }}>
      <p>State Count: {renderCount}</p>
      <p>Ref Count: {countRef.current} (Won't update on screen until render)</p>
      
      <button onClick={incrementRef}>Increment Ref 🤫</button>
      <button onClick={incrementState}>Increment State 📢</button>
    </div>
  );
}

export default ClickCounter;

⚠️ ملاحظات هامة للمبتدئين

  • لا تستخدم useRef لقراءة قيم من المدخلات (Inputs) إذا كنت تريد عرضها لحظياً على الشاشة؛ في هذه الحالة استخدم useState (ما يسمى بالـ Controlled Components).
  • تذكر دائماً أن الوصول للعنصر يكون عن طريق .current. إذا حاولت الوصول لـ inputElement مباشرة بدون .current فلن يعمل الكود.
  • استخدم useRef فقط عندما تحتاج فعلياً للتعامل مع الـ DOM أو تخزين قيم "سرية" لا تؤثر على شكل الصفحة.