المستوى: مبتدئ
لو فتحت أول مشروع React في 2026 ولقيت useEffect بيتنفّذ مرتين كل ما تحفظ الملف، انت مش غلطان وReact مش بايظ. ده تصرّف مقصود من StrictMode، وفهمه بيوفّرلك ساعات debugging أمام bug خفي اسمه Race Condition، اللي بيكسر صفحات بسيطة زي Profile قدّام آلاف المستخدمين كل يوم بدون ما حد ياخد باله.
المشكلة باختصار
كل تطبيق React تقريبًا فيه component بيـ fetch بيانات من API على mount. لو المستخدم بدّل بسرعة من profile رقم 1 لـ profile رقم 2، فيه احتمال إن الطلب الأول البطيء يرجع بعد الطلب التاني السريع. النتيجة: المستخدم يفتح صفحة "أحمد" ويلاقي قدامه بيانات "محمد". الـ network ما عملش حاجة غلط — الـ component هو اللي مفيهوش حماية من الترتيب العكسي.
مفهوم useEffect في كلمتين
useEffect هو الباب اللي بتدخل منه على العالم الخارجي من جوّا component React. أي حاجة مش حسابية بحتة — جلب بيانات، الاشتراك في event، تعديل document.title، الاتصال بـ WebSocket — مكانها الطبيعي جوّاه. بدونه، الـ component بيفضل دالة pure بترسم UI من props و state فقط.
مثال للأطفال أولاً — الجرسون اللي اتلخبط
تخيّل مطعم فيه جرسون واحد. زبون قعد على ترابيزة رقم 4 وطلب شاورما. الجرسون مشي للمطبخ. قبل ما الشاورما تخلص، الزبون قام وغادر، ودخل زبون تاني على نفس الترابيزة وطلب كبدة. الجرسون رجع بالشاورما وحطّها قدّام الزبون الجديد اللي طلب كبدة أصلاً. ده Race Condition بالظبط.
الحل البشري: الجرسون يكتب اسم الزبون على الورقة، ويتأكد قبل ما ينزّل الطلب. الحل البرمجي اسمه AbortController، وهو بيلغي الطلب القديم بمجرد ما الـ component يتغيّر.
التعريف العلمي الدقيق
useEffect دالة بتستقبل callback يتم تنفيذه بعد كل render، ومعها dependency array تحدد متى يعاد التنفيذ. أي عملية async داخل الـ effect لازم تتعامل معاها على أساس إنها قد تكتمل بعد ما الـ component يـ unmount أو بعد ما dependencies تتغيّر. هذا التعريف الكامل موجود حرفيًا في توثيق React الرسمي على react.dev/reference/react/useEffect.
ليه useEffect بيتنفّذ مرتين في Development؟
React منذ الإصدار 18 وحتى 2026 بتشغّل StrictMode تلقائيًا في وضع التطوير. StrictMode بتعمل mount ثم unmount ثم mount مرة تانية، عمدًا، لكل component. ده مش غباء — ده فحص حقيقي بيكشف بدري أي effect مش كاتب cleanup function أو بيتسرّب منه subscription. في production الكود بيتنفّذ مرة واحدة فقط.
لو إجابتك "هشيله من main.jsx عشان مايضايقنيش"، انت بتشيل الـ smoke detector عشان بيزن وانت بتطبخ. ابقَ سيبه شغّال، وعالج الـ effect نفسه عشان يقدر يـ mount ويـ unmount بأمان.