تُبنى تطبيقات React من مكونات (components)، ولكل مكون دورة حياة. يظهر المكون على الشاشة، ويتفاعل مع المعلومات الجديدة، وفي النهاية يختفي. تجاهل هذا الإيقاع وستدفع الثمن؛ حيث ستتسلل تسريبات الذاكرة (memory leaks)، ويتدهور أداء التصيير (render performance)، وينقر المستخدمون على أزرار لم تعد تستجيب لأن المكون المرتبط بها قد تم إلغاء تثبيته (unmounted) منذ عشر دقائق ولكن مستمع الأحداث (event listener) لا يزال يعمل. إن فهم دورة حياة المكون (component lifecycle) ليس مجرد تمرين أكاديمي، بل هو الأساس لكتابة برمجيات تظل موثوقة في ظروف الاستخدام الحقيقية.

فكر في وجود المكون عبر ثلاث مراحل. غالبًا ما يصفها المطورون بالولادة، والنمو، والموت. وتسميها React بالتثبيت (mounting)، والتحديث (updating)، وإلغاء التثبيت (unmounting). لكل مرحلة وظيفة محددة، وكل منها يمنحك لحظة دقيقة لتشغيل الكود أو تنظيفه.

المراحل الثلاث

التثبيت (Mounting) هو الولادة. يتم إنشاء المكون وإدراجه في DOM الخاص بالمتصفح لأول مرة. هذه هي نافذة الإعداد الخاصة بك. إذا كان المكون يحتاج إلى بيانات عن بُعد، فهذا هو الوقت المناسب لطلبها. وإذا كان يحتاج إلى حالة أولية (initial state) يتم حسابها من الـ props، فستقوم بذلك هنا. في عصر مكونات الفئات (class components)، كان هذا من اختصاص componentDidMount. أما مع المكونات الوظيفية (functional components) الحديثة، فستتعامل مع ذلك باستخدام useEffect مع مصفوفة تبعيات فارغة (empty dependency array). التفصيل المهم هو أن كتلة الكود هذه تعمل مرة واحدة فقط، مباشرة بعد أن يضع React العنصر في الصفحة. وهذا يجعلها مثالية للإعداد لمرة واحدة مثل جلب ملف تعريف المستخدم أو قراءة قيمة من localStorage.

التحديث (Updating) هو النمو. المكون المثبت لا يبقى ساكنًا؛ إذ تصل props من المكون الأب، أو تتغير الحالة (state) نتيجة تفاعل المستخدم، أو يعيد المكون الأب تصيير نفسه (re-renders)، مما يجبر المكون الابن على اتباعه. يقوم React بعد ذلك بإعادة تصيير المكون للحفاظ على تزامن واجهة المستخدم (UI) مع بياناتك. تتكرر هذه المرحلة عدة مرات خلال حياة المكون. وفي كل مرة تتغير فيها التبعية (dependency)، يتم تشغيل التأثيرات (effects) مرة أخرى، ويضخ المكون مخرجات جديدة في الـ DOM. ولأن هذه المرحلة تتكرر بشكل متكرر جدًا، فهي أيضًا المكان الذي تبدأ فيه معظم مشاكل الأداء؛ حيث تتراكم الأعمال غير الضرورية هنا بسرعة.

إلغاء التثبيت (Unmounting) هو الموت. يغادر المكون الشاشة، ربما لأن المستخدم انتقل إلى صفحة مختلفة أو لأن التصيير الشرطي (conditional render) قد توقف. في هذه المرحلة، يتم تدمير المكون، لكن العالم الخارجي لا يعرف ذلك دائمًا. تظل المؤقتات (timers) تعمل، وتستمر اتصالات WebSockets في الاستماع، وتظل مستمعات الأحداث (event listeners) على كائن window متصلة. إذا لم تقم بتنظيف هذه العناصر، فستظل تحتفظ بإشارات (references) إلى مكونات ميتة وتتسبب في تسريب الذاكرة. يستهلك المتصفح دورات المعالجة في ملاحقة "أشباح". يوفر لك React دالة تنظيف (cleanup function) خصيصًا لتتمكن من إيقاف الفترات الزمنية (intervals)، وإغلاق الاتصالات، وإزالة المستمعين قبل أن يختفي المكون نهائيًا.

من أساليب الفئات إلى الخطافات

لسنوات، أدار مهندسو React هذه المراحل من خلال مكونات الفئات (class components). كان المنطق البرمجي مقسمًا عبر أساليب (methods) متميزة؛ حيث كنت تجلب البيانات داخل componentDidMount وتستجيب لتغيرات الـ props داخل componentDidUpdate وتقوم بعمليات التنظيف داخل componentWillUnmount. كانت المشكلة هي أن المنطق المرتبط ببعضه ينتهي به الأمر مشتتًا. فميزة واحدة، مثل اتصال دردشة مباشرة، كانت تتطلب كودًا في ثلاث أساليب دورة حياة منفصلة فقط من أجل الاتصال، والتحقق من تغييرات المسار، وفصل الاتصال.

غيرت الخطافات (Hooks) ذلك. يتيح لك خطاف useEffect في المكونات الوظيفية تجميع المنطق حسب الغرض بدلاً من مرحلة دورة الحياة. ومع ذلك، فإن النموذج الذهني يظل متوافقًا بوضوح إذا كنت تعرف أين تبحث.

للتعامل مع التثبيت، اكتب useEffect(() => { ... }, []). تخبر مصفوفة التبعيات الفارغة React أن هذا التأثير ليس له تبعيات خارجية، لذا فإنه يعمل فقط بعد التصيير الأولي. هذا يحل محل componentDidMount.

للتعامل مع التحديثات، قم بتضمين القيم المحددة التي يجب على React مراقبتها: useEffect(() => { ... }, [dependency]). عندما تتغير dependency بين عمليات التصيير،