ما وراء الـ Memo: هندسة تطبيقات شاملة (Universal Apps) عالية الأداء باستخدام React Compiler و Expo
توقف عن تتبع عمليات إعادة الصيرورة (re-renders) يدوياً. تعلم كيف قمت بدمج React Compiler الجديد في سير عمل Expo لتطوير تطبيقات متعددة المنصات وتحقيق أداء يقارب الأداء الأصلي (near-native) دون الحاجة لكتابة useMemo المتكررة.

ما وراء الـ Memo: هندسة تطبيقات شاملة عالية الأداء
لقد قضيت جزءاً كبيراً من مسيرتي المهنية كمهندس برمجيات في تتبع شبح عمليات إعادة الصيرورة (re-renders) غير الضرورية. لقد مررنا جميعاً بهذا الموقف: تغليف كل وظيفة بـ useCallback والتحديق في مصفوفات التبعيات (dependency arrays) في useMemo آملين ألا نكون قد تسببنا في تسريب للذاكرة (memory leak) أو closure قديم. إنه جهد يدوي يشتت انتباهنا عما نريد بناءه حقاً.
مؤخراً، كنت أتعمق في استخدام React Compiler (الذي كان يُعرف سابقاً باسم React Forget) ضمن بيئة Expo. إذا كنت تقوم ببناء تطبيقات شاملة (Universal Apps) تستهدف iOS و Android والويب من كود برمج واحد، فهذا ليس مجرد تحديث بسيط، بل هو تحول جذري في كيفية تفكيرنا في البنية الهندسية عالية الأداء.
ضريبة الـ Memoization
في تطبيقات React Native أو الويب القياسية، تعتبر الـ memoization استراتيجية اختيارية. نحن ننتظر حتى نلاحظ بطئاً في الأداء، ثم نقوم بتشغيل الـ profiler، ونبدأ بإضافة React.memo على المكونات (components). هذا ما أسميه "ضريبة الـ Memoization". إنها تستهلك وقت المطور، وتزيد من تعقيد الكود، وهي هشة للغاية بطبيعتها.
من خلال خبرتي، تفشل الـ memoization اليدوية بطريقتين:
- نقص الـ memoization: يبدو التطبيق بطيئاً على أجهزة Android الضعيفة لأن تغيير حالة واحدة في المكون الأب يؤدي إلى إعادة صيرورة (re-render) شجرة المكونات بالكامل.
- الإفراط في الـ memoization: يقوم المطورون بتغليف كل شيء، مما يؤدي إلى كود ضخم وأخطاء يصعب تتبعها حيث لا يتم تحديث واجهة المستخدم لأن أحد التبعيات قد فُقد.
دخول الـ React Compiler
يغير الـ React Compiler قواعد اللعبة عن طريق نقل مسؤولية الـ memoization من وقت التشغيل (runtime) إلى تحويل وقت البناء (build-time transformation). فهو يقوم بتحليل كود JavaScript/TypeScript الخاص بك ويقوم تلقائياً بإدراج ما يعادل الـ memoization حيثما لزم الأمر، متبعاً "قواعد React".
لماذا يعتبر Expo البيئة المثالية للتجربة
قد يكون دمج الـ compiler في مشروع React Native عادي صداعاً تقنياً. ومع ذلك، مع Expo SDK 51 و 52، أصبح الدمج سلساً بشكل ملحوظ. ولأن Expo يدير إعدادات Metro bundler ومسار Babel/SWC، يمكننا تفعيل الـ compiler ورؤية نتائج فورية عبر جميع المنصات.
التنفيذ التقني: الإعداد
للبدء في بيئة Expo، تحتاج أولاً إلى تثبيت إضافة الـ compiler. في سير عملي الحالي، أستخدم نسخة Babel لأنها الأكثر استقراراً لمسار Metro:
بعد ذلك، قم بتحديث ملف babel.config.js:
ملاحظة: تأكد من أنك تستخدم React 18.3 أو 19-RC لتوفر الـ runtime globals اللازمة لمخرجات الـ compiler.
نتائج ملموسة من أرض الواقع
قمت مؤخراً بإعادة بناء ميزة لوحة تحكم (dashboard) معقدة تعرض بيانات مالية حية. كانت شجرة المكونات عميقة، وتتضمن رسوماً بيانية متعددة (SVG عبر react-native-svg) وقوائم مفلترة.
الحالة "قبل"
كان لدي مكون PriceRow يبدو بهذا الشكل للحفاظ على الأداء:
الحالة "بعد" مع الـ Compiler
مع React Compiler، قمت بحذف كل ذلك الكود المتكرر. أصبح الكود أنظف، وأكثر قابلية للقراءة، والأهم من ذلك—أصبح أسرع لأن الـ compiler أكثر دقة وتفصيلاً مما يمكن أن يكون عليه أي بشري.
في تجاربي على جهاز Android اقتصادي (سلسلة Moto G)، انخفض زمن تأخير التفاعل (interaction latency) بنسبة تقارب 30% لأن الـ compiler قام بتحسين مسار الصيرورة بالكامل، وليس فقط المكونات الطرفية (leaf nodes).
القيود الهندسية
الأمر ليس سحراً؛ بل هو هندسة برمجية. الـ compiler صارم للغاية. إذا كنت تتساهل في تطبيق Rules of React (مثل تغيير الـ props مباشرة أو استدعاء الـ hooks بشكل مشروط)، فسيقوم الـ compiler ببساطة بتجاوز تلك المكونات.
أوصي باستخدام إضافة React Compiler ESLint plugin، فهي تكتشف هذه المشكلات قبل أن تحاول بناء المشروع:
الأداء الشامل: الويب مقابل التطبيقات الأصلية (Native)
أحد أكبر المكاسب التي وجدتها كانت في منصة الويب. عند استخدام Expo Router لبناء مواقع متوافقة مع محركات البحث (SEO-friendly)، يقلل React Compiler بشكل كبير من حجم العمل الذي يقوم به الخيط الرئيسي (main thread) أثناء عملية الـ hydration. أما بالنسبة للهواتف، فهو يقلل من حركة البيانات عبر الـ bridge (أو عبء JSI في المعمارية الجديدة New Architecture) بسبب إرسال عدد أقل من التحديثات غير الضرورية إلى الطبقة الأصلية (native layer).
كلمات ختامية
نحن ندخل عصراً يصبح فيه الأداء تفصيلاً من تفاصيل تنفيذ اللغة/المترجم بدلاً من كونه مهمة تحسين يدوية. بالنسبة لكبار المهندسين، هذا يعني أنه يمكننا التوقف عن مراجعة مصفوفات التبعيات في الكود والبدء في التركيز على البنية الهندسية عالية المستوى، وأنماط إدارة الحالة، وتجربة المستخدم.
إذا كنت تستخدم Expo، جرب تفعيله لمجلد ميزة واحدة أولاً باستخدام إعداد sources في الإضافة. السرعة قد تفاجئك.
استمروا في البناء.