إيه هو ForwardRef في رياكت (React) وإمتى تحتاجه بجد؟
أهلاً بيك يا صديقي المبرمج في مقال جديد من سلسلة شروحات تطوير الـ ويب (Web Development). لو انت شغال بـ رياكت (React) بقالك فترة، غالباً قابلتك المشكلة دي: بيكون عندك مكون أب (Parent Component) وعايز تتحكم في عنصر دوّم (DOM Element) جوه مكون ابن (Child Component)، زي مثلاً انك تعمل تركيز أو (Focus) على حقل إدخال (Input) أول ما الصفحة تفتح، أو تحرك السكرول لمكان معين.
الطبيعي في رياكت إننا بنمرر البيانات من الأب للابن عن طريق الخصائص أو (Props)، بس لما تيجي تمرر مرجع أو (Ref) بالطريقة العادية، هتلاقي رياكت بيطلعلك تحذير ومفيش حاجة هتشتغل! ليه؟ لأن الـ Refs مش بتمشي مع الـ Props العادية. هنا بقى بيجي دور البطل بتاعنا النهارده: ForwardRef.
Table of contents [Show]
يعني ايه اصلا Ref وليه مش بنعرف نمرره للابن عادي؟
الـ (References) باختصار هي طريقة في رياكت عشان نمسك عنصر معين في الـ DOM مباشرة، من غير ما نعمل إعادة رندر (Re-render) للمكون. بنعمل ده باستخدام هوك الـ (useRef).
المشكلة بتظهر لما بنحب نصمم مكون ابن قابلة لإعادة الاستخدام (Reusable Component)، زي زرار سفلي أو حقل إدخال مخصص. المكون الأب بيبقى عايز يمسك الـ DOM element الحقيقي اللي جوه المكون الابن. لو جربت تمرر الـ ref كـ prop عادي، رياكت هيعتبرها prop عادية ومش هيديها الـ DOM node المطلوب، وهنا بنحتاج نستخدم خاصية توريث المراجع أو (Forwarding Refs).
إزاي بنستخدم ForwardRef في الكود العملي؟ (Tutorials)
تعال نشوف مثال عملي وبسيط يوضح الموضوع. تخيل إن عندنا مكون ابن اسمه CustomInput وعايزين الأب يتحكم في الـ Focus بتاعه.
الطريقة الصحيحة بتكون كالتالي:
import React, { useRef, forwardRef } from 'react';
// بنستخدم forwardRef عشان نخلي المكون يستقبل الref كمعامل تاني
const CustomInput = forwardRef((props, ref) => {
return (
<div>
<input type="text" ref={ref} placeholder="اكتب حاجة هنا..." {...props} />
</div>
);
});
export default CustomInput;
دلوقتي، تعال نشوف الأب هيستخدم المكون ده إزاي ويتحكم فيه:
import React, { useRef } from 'react';
import CustomInput from './CustomInput';
function ParentComponent() {
// بنعمل إنشاء للـ ref
const inputRef = useRef(null);
const handleFocus = () => {
// بننده على الـ focus مباشرة من الـ DOM
inputRef.current.focus();
};
return (
<div>
<CustomInput ref={inputRef} />
<button onClick={handleFocus}>اضغط هنا عشان تعمل Focus</button>
</div>
);
}
بالطريقة دي، قدرنا نربط الـ Ref اللي عند الأب بالعنصر الحقيقي (الـ input) الموجود جوه الابن، من غير ما نكسر قواعد رياكت في تدفق البيانات.
إمتى فعلاً هتحتاج تستخدم ForwardRef في مشاريعك؟ (Coding Challenges)
مش كل وقت هنحتاج نستخدم الـ ForwardRef، واستخدامه الكتير ممكن يعقد الكود (Over-engineering). لكن فيه حالات رئيسية ضروري تستخدمه فيها:
- التحكم في عناصر الـ DOM المباشرة: زي الـ Focus، الـ Scroll، أو تحديد حجم عنصر معين (Animations).
- مكتبات المكونات الجاهزة (Component Libraries): لو بتعمل مكتبة زي الـ UI Library الخاصة بيك وبتصدر مكونات للمطورين التانين، لازم تدعم الـ Refs عشان اللي يستخدم مكتبتك يعرف يتحكم في العناصر براحته.
- التعامل مع الوسائط المتعددة: زي تشغيل وإيقاف فيديوهات الـ HTML5 (Video / Audio tags) من خلال الأب.
خاتمة ونصيحة من أخ
استخدام الـ ForwardRef هو واحدة من الأدوات المتقدمة شوية في رياكت (Advanced React Concepts)، بس هيسهل عليك كتير لما تقابل مشااكل تخص التحكم المباشر في الـ DOM. نصيحتي ليك كـ مبرمج: متستخدمش الـ Refs إلا للضرورة القصوى، لأن فلسفة رياكت الأساسية قايمة على البيانات (Data-driven) مش التلاعب المباشر بالـ DOM. دايماً فكر الأول لو فيه طريقة بالـ State أو الـ Props تقضي الغرض قبل ما تلجأ للـ Refs.