في هذا الدرس 6تصفّح المواضيع
تُعيد React افتراضياً تنفيذ كامل جسم دالة المكون عند كل تصيير. ورغم أن العمليات البسيطة على عشرات العناصر لا تستغرق سوى أجزاء ضئيلة من الألف من الثانية، فإن فلترة أو فرز آلاف السجلات الإحصائية عند تبديل زر عرض جانبي غير مرتبط بها يُهدر وقت المعالج بلا مبرر.
هنا يبرز خطاف useMemo(calculateValue, dependencies) الذي يخزن القيمة الناتجة من عملية حسابية نقية بين مرات التصيير، ولا يعيد حسابها إلا إذا تغير أحد عناصر مصفوفة الاعتماديات وفق فحص Object.is():
import { useMemo, useState } from 'react';
const visible = useMemo(() => {
return COURSES.filter((c) =>
c.title.toLowerCase().includes(query.toLowerCase())
);
}, [query]);
رأينا في الدرس السابق كيف يكسر الكائن المضمن تغليف React.memo، ولكن ماذا نفعل حين تعتمد قيم ذلك الكائن على حالة داخلية متغيرة فلا يمكن رفعه خارج المكون؟
يحل خطاف useMemo() هذه المشكلة بدقة عبر كتابة useMemo(() => ({ unit, dense }), [unit, dense])؛ إذ يعيد نفس المرجع في الذاكرة طالما لم تتغير عناصر الاعتمادية، مما يحافظ على ثبات المكونات المغلفة بـ memo() واعتماديات useEffect() معاً.
تماماً كما يحدث مع الكائنات المضمنة، فإن تعريف دالة حدث داخل المكون الأب ينشئ مرجع دالة جديداً في كل تصيير؛ فإذا مررت هذه الدالة لمكون فرعي مغلف بـ memo() ستفشل مقارنة المراجع ويعاد رسم الابن في كل مرة.
لتثبيت مرجع الدالة نستخدم خطاف useCallback(fn, dependencies). تذكر القاعدة الفاصلة ببساطة: يخزن useMemo ناتج استدعاء الدالة، بينما يخزن useCallback تعريف الدالة نفسها لتُستدعى لاحقاً عند وقوع الحدث:
import { memo, useCallback, useState } from 'react';
const handleSelect = useCallback((trackId) => {
setSelectedId(trackId);
}, []);
// Safe to pass to memoized child:
// <TrackList onSelect={handleSelect} />
انتبه لتفصيل شائع: إذا قرأت دالة الحدث مصفوفة الحالة مباشرة عبر كتابة setTasks([...tasks, next])، فستضطر لإدراج [tasks] في مصفوفة اعتماديات useCallback، مما يعيد إنشاء الدالة عند كل تعديل على المصفوفة!
أما عند استخدام دالة التحديث الوظيفية setTasks((prev) => [...prev, next])، فلا تعود الدالة بحاجة لقراءة المتغير الخارجي، وتفرغ مصفوفة الاعتماديات إلى [] فيبقى مرجع الدالة ثابتاً طوال عمر المكون:
const toggleDone = useCallback((id) => {
setItems((prev) =>
prev.map((it) =>
it.id === id ? { ...it, done: !it.done } : it
)
);
}, []); // Zero state dependencies!
احذر من التذكر المبكر غير المبرر (Premature Memoization). إن تغليف عملية دمج نصين بسيطين بـ useMemo() أو تغليف كل نقرة زر عادية بـ useCallback() يثقل القراءة ويزيد أعباء صيانة الاعتماديات دون أي فرق يشعر به المستخدم.
احتفظ بهذين الخطافين لحالتين واضحتين فقط: العمليات الحسابية الثقيلة التي تستغرق نحو 1 مللي ثانية فأكثر في أداة القياس، أو الكائنات والدوال الممررة لمكونات مغلفة بـ memo() أو داخل مصفوفات اعتماديات الخطافات.
في منظومة React الحديثة، يبرز مترجم React الحديث (React Compiler) كإضافة بناء في Vite تحلل المكونات الملتزمة بقواعد النقاء وتقوم بأتمتة التذكر تلقائياً للقيم المحسوبة وعناصر الواجهة والدوال أثناء عملية البناء، مما يقلص الحاجة لكتابة التغليف اليدوي المتكرر في المشاريع الجديدة مع بقاء فهمك لثبات المراجع أساسياً لتشخيص الحالات الدقيقة. قارن الأدوات الأربع في الجدول التالي:
| الأداة البرمجية | ما الذي تخزنه بالضبط | حالة الاستخدام الهندسية الأساسية |
|---|---|---|
| تغليف React.memo | مخرجات التصيير لمكون فرعي كامل | تخطي رسم المكون الابن عند ثبات جميع خصائصه |
| خطاف useMemo | القيمة الناتجة عن دالة حسابية نقية | فلترة آلاف السجلات أو تثبيت مراجع الكائنات الديناميكية |
| خطاف useCallback | مرجع تعريف الدالة نفسها في الذاكرة | تمرير دوال أحداث ثابتة للمكونات المغلفة بـ memo |
| مترجم React Compiler | القيم والدوال وعناصر JSX وقت البناء | أتمتة التذكر الدقيق تلقائياً للمكونات النقية |
ملخص الدرس
حصاد الدرسمراجعة مركّزة لأهم المفاهيم والقواعد الهندسية التي أتقنتها في هذا الدرس قبل التطبيق العملي
ماذا تعلّمت في هذا الدرس؟
أتقنت في هذا الدرس تخزين العمليات الحسابية المكلفة وتثبيت الكائنات الديناميكية عبر useMemo، وحفظ مراجع الدوال مع دوال التحديث الوظيفية عبر useCallback، وتجنب التذكر المبكر وفهم دور مترجم React Compiler الحديث. الخطوة التالية: انتقل الآن إلى الدرس رقم 45 «تقسيم الكود والتحميل الكسول عبر React.lazy وSuspense» لمواصلة البناء التراكمي المتدرج في مسار React الحديث.
سجّل الدخول لحفظ تقدمك
تابع إنجاز المواضيع والمصطلحات والمهام، وكمّل من آخر خطوة على أي جهاز.
المصطلحات4
راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.
- 01 Memoization التذكر المؤقت
- تقنية تحسين أداء تحفظ نتيجة عملية نقية مكلفة وتعيدها فوراً عند تكرار نفس المدخلات دون إعادة الحساب.
- للمراجعة
- 02 useMemo خطاف useMemo
- خطاف في React يحفظ القيمة المرجعة من دالة حسابية نقية بين مرات التصيير حتى تتغير إحدى اعتمادياته.
- للمراجعة
- 03 useCallback خطاف useCallback
- خطاف في React يحفظ مرجع الدالة نفسها عبر مرات التصيير لتمريرها بثبات للمكونات المذكرة أو التأثيرات.
- للمراجعة
- 04 React Compiler مترجم React الحديث
- أداة بناء رسمية تحلل المكونات الدالية النقية وتطبق حفظ القيم والمراجع تلقائياً دون تغليف يدوي كثيف.
- للمراجعة
لا توجد بطاقات تطابق البحث والتصفية.
اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.
الاختصارات4
راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.
- 01 CPU CPU
- Central Processing Unit
- دورات المعالجة التي يوفرها تخطي إعادة فرز وفلترة المصفوفات الكبيرة عند ثبات المدخلات.
- للمراجعة
- 02 HMR HMR
- Hot Module Replacement
- ميزة التحديث اللحظي للوحدات في Vite أثناء التطوير والتي تعيد تهيئة ذاكرة الخطافات بأمان.
- للمراجعة
- 03 AST AST
- Abstract Syntax Tree
- شجرة التحليل النحوي للكود التي يفحصها مترجم React وقت البناء لأتمتة التذكر.
- للمراجعة
- 04 UI UI
- User Interface
- واجهة المستخدم التي تحافظ على سلاستها عند عزل وتخزين الحسابات المشتقة الثقيلة.
- للمراجعة
لا توجد بطاقات تطابق البحث والتصفية.
اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.
مهامك قبل الاختبار
خطوة صغيرة كل مرة. وإنجاز تقدر ترجع له.
-
شغّل مثال CourseExplorer واضغط زر تبديل التخطيط خمس مرات وتأكد أن عداد تشغيل الفلترة يظل ثابتاً ولا يزيد إلا عند الكتابة في حقل البحث.
-
اضغط زر التبديل لأحد المهام في مثال قائمة المهام وتأكد من بقاء عداد التصيير للصفين الآخرين ثابتاً دون زيادة.
تأشير المهمة إقرار منك بإتمامها، وليس تصحيحًا آليًا للكود. يُحفظ تقدمك في حسابك.
اختبر فهمك.
ووصلها للإتقان.
كل سؤال خطوة لقدّام. اختار، اكتب كود، وشوف نتيجتك فورًا.
أكمل المهام، واجمع كل الإجابات الصحيحة. أقل من 100%؟ راجع وأعد المحاولة.
الأسئلة متاحة للاطلاع. سجّل الدخول للتفاعل وحفظ تقدمك.
لمحة عن التحدي10 أسئلة تنتظرك +
ما الفرق الجوهري بين خطاف useMemo وخطاف useCallback؟
يخزن useMemo النتيجة المحسوبة من استدعاء الدالة، بينما يخزن useCallback مرجع تعريف الدالة نفسها.
تعمل الدالة الممررة إلى useMemo أثناء طور التصيير ويجب أن تظل دالة نقية خالية من الآثار الجانبية.
صواب؛ فالطلبات الشبكية والتعديلات الخارجية مكانها خطاف useEffect أو دوال الأحداث وليس داخل useMemo.
كيف تمنع كائن إعدادات ديناميكياً يعتمد على unit وshowTrend من كسر تغليف React.memo للمكون الفرعي؟
بتغليف إنشاء الكائن داخل useMemo مع تحديد المتغيرين في مصفوفة الاعتماديات.
هل يحقق تغليف دالة بـ useCallback تسريعاً في التصيير إذا مُررت فقط لعنصر زر HTML عادي؟
لا؛ فعناصر HTML العادية لا تفحص ثبات المرجع عبر React.memo لذا لا يوفر ذلك أي إعادة تصيير.
داخل useCallback، كيف تحدّث مصفوفة الحالة tasks دون الحاجة لإدراج [tasks] في مصفوفة الاعتماديات؟
باستخدام دالة التحديث الوظيفية setTasks(prev => ...) التي تستلم أحدث حالة مباشرة من React.
يمكن الاعتماد على useMemo كقاعدة بيانات دائمة مضمونة بعدم إعادة الحساب إطلاقاً تحت أي ظرف.
خطأ؛ فخطاف useMemo مخصص لتحسين الأداء فقط وقد تعيد React حسابه عند تحرير الذاكرة أو التحديث السريع.
وفق إرشادات React الرسمية، ما الزمن التقريبي الذي يجعل العملية الحسابية النقية جديرة بالتخزين عبر useMemo؟
نحو 1 مللي ثانية فأكثر عند قياس زمن التنفيذ.
يُعد تغليف كل متغير وكل دالة في المشروع بـ useMemo وuseCallback أفضل ممارسة دائماً حتى بدون قياس.
خطأ؛ فالتذكر المفرط غير المبرر يعقد قراءة الكود ويضيف فحوصات اعتماديات بلا مكسب حقيقي.
ما الدور الذي يؤديه مترجم React Compiler الحديث في منظومة البناء؟
يحلل المكونات النقية وقت البناء ويطبق حفظ القيم والدوال وعناصر الواجهة تلقائياً.
أي تعبير مما يلي يكافئ وظيفياً استدعاء useCallback(fn, deps)؟
إرجاع تعريف الدالة نفسها من داخل useMemo بالصيغة useMemo(() => fn, deps).