يوفر لك React طريقتين للحفاظ على البيانات حية داخل المكون: useState و useRef. للوهلة الأولى، يبدوان متشابهين. كلاهما يعيد شيئاً يمكنك قراءته، وكلاهما يصمد أمام عمليات إعادة الصيرورة (re-renders)، وكلاهما يسمح لك بتذكر قيمة من نقرة إلى أخرى. ومع ذلك، إذا اخترت الخيار الخاطئ، فسينتهي بك الأمر إما بشاشة ترفض التحديث أو بسلسلة لا تنتهي من عمليات إعادة الصيرورة غير الضرورية. الخيار لا يتعلق بالصيغة البرمجية (syntax)، بل يتعلق بما إذا كان React بحاجة إلى المعرفة.

ما يفعله كل Hook فعلياً

useState هو وسيلة التواصل الرسمية لـ React مع المكون. عندما تستدعيه، تحصل على قيمة ودالة تعيين (setter function). يتتبع React تلك القيمة كجزء من هوية المكون. عندما يتم تشغيل دالة التعيين، يقول React: "لقد تغير شيء ما"، ويجدول عملية إعادة صيرورة جديدة حتى تتمكن الشاشة من مواكبة التغيير.

أما useRef فليس أكثر من كائن JavaScript بسيط يحتوي على خاصية current. يعدك React بتسليمك نفس مرجع الكائن تماماً في كل عملية إعادة صيرورة. إنه لا يراقب ما بداخله. تغيير قيمة someRef.current يحدث بصمت، ولن يتفاعل React مع ذلك.

هذا الصمت هو الهدف الأساسي. الـ Refs هي مخرج طوارئ (escape hatch)، وليست بديلاً للحالة (state).

الانقسام في عملية الصيرورة (Rendering)

إذا قمت بتغيير الحالة (state)، يعاد صيرورة المكون. هذا هو السلوك الذي يتوقعه معظم المبتدئين، وهو بالضبط ما تريده عندما يجب أن تظهر البيانات الجديدة على الشاشة. عداد، حقل نموذج، قائمة مستخدمين تم جلبها—إذا كان المستخدم يراها، فمن المحتمل أنها تنتمي إلى الحالة. تدفق البيانات الكامل في React مبني حول فكرة أن تغييرات الحالة تنبه المُصيّر (renderer) لمزامنة الـ DOM.

إذا قمت بتغيير ref، فلن يحدث شيء مرئياً. يتم تحديث المتغير فوراً وبشكل متزامن، لكن المكون لا يعاد صيرورته. وهذا يجعل الـ refs مثالية للقيم التي تدعم العمليات الداخلية للمكون دون أن تكون جزءاً من المخرجات المرئية. فكر في معرفات المؤقتات (timer IDs)، أو لقطات الخصائص السابقة (previous prop snapshots)، أو مقابض الـ DOM المباشرة. واجهة المستخدم لا تهتم بمعرف الفترة الزمنية (interval ID) الذي يشغل التمرير التلقائي في معرض الصور (carousel)؛ هي تهتم فقط بالشريحة المرئية. لذا، ينتمي معرف الفترة الزمنية إلى ref.

متى تكون الحالة (State) هي الأداة المناسبة

استخدم useState في أي وقت تكون فيه القيمة جزءاً من سطح واجهة المستخدم الخاصة بك.

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

العدادات والمفاتيح (toggles) هي ركيزة أخرى. زر يزيد النتيجة، علامة فتح/إغلاق النافذة المنبثقة (modal)، فهرس التبويب—كل هذه تتدفق عبر الحالة لأن مخرجات الصيرورة تتغير مع القيمة. حتى القيم المشتقة، مثل قائمة مصفاة تعتمد على سلسلة بحث، تبدأ عادةً بالحالة لأن القيمة المصدر مرئية للمستخدم.

هناك أيضاً فارق دقيق في التوقيت يستحق الفهم. تحديثات الحالة غير متزامنة ومجمعة (batched). إذا استدعيت setCount(count + 1) ثلاث مرات داخل معالج حدث واحد، فلن يقوم React بالصيرورة ثلاث مرات، بل يجمعها في تحديث واحد. المتغير count داخل الدالة التي تعمل يظل أيضاً قديماً (stale) حتى عملية الصيرورة التالية. هذا التجميع هو ميزة، فهو يحافظ على سرعة التطبيقات. لكن هذا يعني أنه لا يمكنك توقع أن يعكس متغير الحالة القيمة الجديدة في السطر التالي مباشرة.

متى تنقذ الـ Refs الموقف

استخدم useRef للأعمال الهيكلية، وليس