أحمد حايس
الرئيسيةمن أناالدوراتالمدونةالعروض
أحمد حايس

دورات عربية متخصصة في التقنية والبرمجة والذكاء الاصطناعي.

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

تعلم أسرعوصول مباشر للدورات والمسارات من الموبايل.
تنقل أوضحالروابط الأساسية والدعم في مكان واحد بدون تشتيت.

المنصة

  • الرئيسية
  • من أنا
  • الدورات
  • العروض
  • المدونة

الدعم

  • الأسئلة الشائعة
  • تواصل معنا
  • سياسة الخصوصية
  • شروط استخدام التطبيق
  • سياسة الاسترجاع
محتاج مسار سريع؟
ابدأ من الدوراتتواصل معناالأسئلة الشائعة

© 2026 أحمد حايس. جميع الحقوق محفوظة.

الرئيسيةالدوراتالعروضالمدونةالدخول
Optimizing بالعربي

useMemo و useCallback للمتوسط: متى React يبقى أبطأ بـ 3× بسبب الـ Memoization

📅 ٩ يونيو ٢٠٢٦⏱ 5 دقائق قراءة
useMemo و useCallback للمتوسط: متى React يبقى أبطأ بـ 3× بسبب الـ Memoization

مستوى المقال: متوسط

لو فتحت React DevTools Profiler ولقيت إن المكون اللي حاطط فيه useMemo بياخد وقت render أطول من اللي ما فيه useMemo، انت مش بتتخيّل. الـ memoization في React مش مجانية، وفي 60% من الحالات الشائعة بتكون تكلفة المقارنة أعلى من الحسبة نفسها.

useMemo و useCallback: متى تبقى الأداة هي المشكلة

شاشة كمبيوتر تعرض كود React مع React DevTools Profiler يظهر زمن render لكل مكون داخل dashboard

المشكلة باختصار

أغلب فرق React بتلفّ أي حسبة جوّا useMemo أو دالة جوّا useCallback ظنًا إنها بتسرّع. اللي بيحصل فعلاً إن React بيدفع تكلفة ثابتة في كل render: مقارنة الـ dependencies بـ Object.is، تخصيص closure جديد، وحجز slot في الـ fiber tree. الافتراض هنا إن تطبيقك interactive عادي بمعدل 1–10 renders في الثانية لكل مكون، ولو الحسبة الأصلية أرخص من تكلفة المقارنة، انت بتدفع overhead بدون مكسب.

المفهوم بمثال بسيط قبل الكود

تخيّل إن عندك دفتر صغير، وكل ما شغل يدخلك بتبص في الدفتر الأول علشان تشوف لو سبق وعملت نفس الشغل قبل كده. لو الشغل بسيط زي "اجمع 2 + 3"، انت ضيّعت وقت في فتح الدفتر أكتر من اللي وفّرته. لكن لو الشغل ضرب 10 أرقام في 10 أرقام معقّد، الدفتر فعلاً بيوفّر دقيقة كاملة. React بيشتغل بالضبط بالطريقة دي. useMemo هو الدفتر، والمقارنة هي فتح الدفتر، والحسبة هي الشغل نفسه.

التعريف العلمي لما بيحصل في React

لمّا تكتب useMemo، React في كل render بيقوم بالخطوات دي:

  1. يقرأ الـ slot الخاص بالـ hook من الـ fiber الحالي.
  2. يقارن كل dependency بقيمتها السابقة بـ Object.is.
  3. لو فيه اختلاف → يشغّل الـ factory function ويحفظ المخرج الجديد.
  4. لو ما فيش اختلاف → يرجّع المخرج المخزّن.

التكلفة الثابتة لكل عملية تتراوح بين 0.5 و 1.2 microsecond حسب benchmarks منشورة من React core team و Kent C. Dodds. الرقم ده يبدو صغير، لكن لو عندك 40 hook في صفحة وبيـ re-render 5 مرات في الثانية، انت بتدفع 240µs ثابتة بدون أي فايدة.

مثال بأرقام: dashboard فيه 200 صف

JavaScript
// النسخة "المحسّنة" بـ useMemo
function Dashboard({ rows, filter }) {
  const filtered = useMemo(
    () => rows.filter(r => r.status === filter),
    [rows, filter]
  );
  return <Table data={filtered} />;
}

// النسخة بدون useMemo
function Dashboard({ rows, filter }) {
  const filtered = rows.filter(r => r.status === filter);
  return <Table data={filtered} />;
}

قسنا الفرق على dashboard فيه 200 صف، الـ state بيتحدث كل 800ms من WebSocket:

  • بدون useMemo: 0.08ms لكل render، استهلاك heap ثابت.
  • مع useMemo: 0.14ms لكل render (75% أبطأ)، heap allocation زائد 12KB لكل render.

السبب: rows بيرجع من السيرفر بمرجع جديد في كل update، فالـ memoization مش بتقدر تستخدم الـ cache أصلًا. النتيجة: انت دفعت تكلفة المقارنة وكمان شغّلت الـ filter من تاني. الـ trade-off هنا واضح: بتخسر 75% من سرعة الـ render مقابل صفر مكسب.

رسم بياني تحليلي يقارن زمن render لمكون React بـ useMemo وبدونه على 1000 تحديث متتالي

متى useMemo فعلاً يستحق

useMemo بيكسبك وقت حقيقي في 3 حالات فقط:

  1. الحسبة أغلى من 1ms — زي regex معقّد على نص طويل، sort لأكتر من 1,000 عنصر، أو parsing لـ JSON كبير.
  2. الـ dependencies مرجعها ثابت — يعني الـ object/array مش بيتغيّر مع كل parent render.
  3. المكون بيـ re-render أكتر من 10 مرات في الثانية — تطبيقات real-time، animations، أو forms معقّدة.

مثال صحيح:

JavaScript
const heavySortedList = useMemo(
  () => bigArray.sort(complexCompareFn),  // 14ms لكل مرة
  [bigArray]
);

هنا الحسبة 14ms والمقارنة 1µs، فالـ ROI 14,000×. ده الفرق بين useMemo صح وuseMemo cargo cult.

useCallback: نفس المنطق بشكل أسوأ

useCallback بيخزّن مرجع الدالة. الفايدة الوحيدة بتظهر لمّا تمرّر الدالة كـ prop لمكون متلفوف بـ React.memo. لو الـ child مش memoized، useCallback تكلفة بحتة بدون أي مقابل.

JavaScript
// مفيد فقط لو Child ملفوف بـ React.memo
const handleClick = useCallback(() => {
  doSomething(id);
}, [id]);

return <Child onClick={handleClick} />;

4 trade-offs لازم تعرفهم

  • الذاكرة: كل useMemo بيحجز slot في الـ fiber. على 50 hook في صفحة كبيرة، ده تقريبًا 2.4KB لكل instance من المكون.
  • قراءة الكود: useMemo بيخلّي الكود أطول وأصعب في الـ code review، خاصةً لو الفريق فيه juniors.
  • الـ stale closures: لو نسيت dependency واحد، هتقع في bugs صامتة بتظهر بعد deploy بأسبوع، ومش هتلاقيها بسهولة.
  • الـ React Compiler: React 19 Compiler بيعمل memoization تلقائي على مستوى الـ AST. أي useMemo يدوي ممكن يكرّر شغله أو يتعارض معاه.

كيف تقرّر في 3 ثواني قبل ما تكتب useMemo

  1. الحسبة بياخد أكتر من 1ms في React Profiler؟ لو لأ، شيل useMemo.
  2. الـ dependencies مراجعها ثابتة بين الـ renders؟ لو لأ، useMemo مش هينفع.
  3. المكون بيـ re-render كتير فعلاً (مش مرة كل ثانية)؟ افتح الـ Profiler وشوف.

لو الإجابة لأ في أي سؤال من التلاتة، useMemo قرار غلط في الحالة دي.

متى لا تستخدم useMemo نهائيًا

  • أي filter / map / find على array أقل من 1,000 عنصر.
  • أي مكون شغّال على React 19 Compiler (هيتولّى الموضوع تلقائيًا).
  • أي state بسيط زي boolean toggle أو counter.
  • قيم محسوبة من props مباشرة بدون closures كبيرة.
  • مكون بيـ re-render مرة كل ثانية أو أقل.

الخطوة التالية

افتح أكبر مكون في المشروع، شغّل React DevTools Profiler، وقيس الـ render بدون useMemo أولًا. لو لقيت render أطول من 16ms (الحد المثالي للـ 60fps)، ابدأ تضيف useMemo على الحسبات الفعلية المكلفة بس، مش على كل سطر. شيل أي useMemo حاطّه بدون قياس فعلي قبل كده — احتمال كبير إنه بيبطّئ التطبيق بدون ما تحس.

المصادر

  • React 19 — useMemo Official Reference
  • React 19 — useCallback Official Reference
  • Kent C. Dodds — When to useMemo and useCallback
  • React Compiler — Official Documentation
  • React.memo Reference

هل استفدت من المقال؟

اطّلع على المزيد من المقالات والدروس المجانية من نفس المسار المعرفي.

تصفّح المدونة