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

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

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

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

المنصة

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

الدعم

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

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

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

قائمة React بتجمّد المتصفح؟ Virtualization بيخلّيها 40× أسرع

📅 ٢٥ أبريل ٢٠٢٦⏱ 5 دقائق قراءة
قائمة React بتجمّد المتصفح؟ Virtualization بيخلّيها 40× أسرع

لو عندك جدول فيه 5000 صف بيتعمله render في React، المتصفح ممكن يتجمّد 4–5 ثواني قبل ما المستخدم يقدر يـ scroll. الحل مش في إعادة كتابة الكومبوننت ولا في React.memo. الحل اسمه Virtualization، وبيقلّل عدد الـ DOM nodes من 5000 لـ 20 تقريبًا، والـ initial render من ثواني لمللي ثانية.

Virtualization في React: العلاج الحقيقي لقوائم بطيئة

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

المتصفح بيرسم كل عنصر HTML في الذاكرة، يحسب موقعه (layout)، ثم يرسمه (paint). لو عندك قائمة فيها 5000 عنصر، حتى لو كل عنصر بسيط، بتعمل 5000 layout calculation. ده بيستهلك الـ main thread ويوقف الـ UI لثواني.

الـ React.memo و useMemo بيحلّوا مشكلة re-render، لكن مبيقللوش عدد العناصر في الـ DOM. المشكلة هنا مش في React نفسها، هي في الـ DOM.

شاشة محرر كود تعرض مكوّن React مع منطق رندر قائمة طويلة بألوان متباينة

افهم Virtualization من خلال مثال بسيط

تخيّل إنك في مكتبة فيها 10 آلاف كتاب، لكن الرفوف اللي قدامك مش بتسع غير 20 كتاب في الوقت الواحد. لو حد طلب منك تحط كل الكتب على الرف، هتقعد ساعة، وهيقع نص الرف. الحل المنطقي: تحط الـ 20 كتاب اللي قدام الزائر دلوقتي بس، ولما يمشي شوية، تبدّلهم بـ 20 جداد من الكتب اللي وراهم.

ده بالظبط اللي بيحصل في Virtualization. الكود بيرسم في الـ DOM الـ 20 عنصر اللي ظاهرين في الـ viewport بس. أول ما المستخدم يـ scroll، بنشيل العناصر اللي خرجت من الشاشة ونحط مكانها العناصر الجديدة. الباقي مش موجود في الـ DOM أصلًا.

التعريف العلمي الدقيق

Virtualization (أو Windowing) أسلوب رندر بيحسب أبعاد العنصر الواحد + عدد العناصر الكلي، فيقدر يعرف "النافذة" المرئية حاليًا في الـ viewport. بيرسم العناصر اللي داخل النافذة فقط + بافر صغير فوق وتحت اسمه overscan لتجنّب وميض الـ scroll.

النتيجة: عدد العناصر في الـ DOM بيقعد ثابت (10–30 عنصر) مهما كان حجم البيانات الكلي 5000 ولا 50,000. زمن الـ initial render بينخفض من O(n) إلى O(window_size). المكتبة بتحجز div خارجي بارتفاع كامل = itemHeight × itemsCount علشان الـ scrollbar يفضل يمثّل الحجم الحقيقي.

الحل التطبيقي بـ TanStack Virtual

هستخدم TanStack Virtual (الاسم القديم react-virtual). أخف من react-window، بيدعم variable height، ومستقل عن أي UI library.

Bash
npm install @tanstack/react-virtual

كود قائمة 10 آلاف عنصر، قابل للنسخ مباشرة:

TSX
import { useRef } from 'react';
import { useVirtualizer } from '@tanstack/react-virtual';

export function VirtualList({ items }: { items: string[] }) {
  const parentRef = useRef<HTMLDivElement>(null);

  const rowVirtualizer = useVirtualizer({
    count: items.length,
    getScrollElement: () => parentRef.current,
    estimateSize: () => 48,
    overscan: 5,
  });

  return (
    <div ref={parentRef} style={{ height: 600, overflow: 'auto' }}>
      <div
        style={{
          height: rowVirtualizer.getTotalSize(),
          position: 'relative',
        }}
      >
        {rowVirtualizer.getVirtualItems().map((virtualRow) => (
          <div
            key={virtualRow.key}
            style={{
              position: 'absolute',
              top: 0,
              left: 0,
              width: '100%',
              height: virtualRow.size,
              transform: `translateY(${virtualRow.start}px)`,
            }}
          >
            {items[virtualRow.index]}
          </div>
        ))}
      </div>
    </div>
  );
}

الـ estimateSize هو تقدير ابتدائي لارتفاع العنصر. لو الارتفاعات متفاوتة، استخدم measureElement لقياس فعلي بعد الرندر.

الأرقام: قبل وبعد

قياس على Chrome DevTools Performance — قائمة 5000 صف، كل صف فيه نص + button + avatar:

  • Initial render: من 4200ms لـ 95ms (تحسّن ~44×).
  • عدد DOM nodes: من 25,000 لـ 110.
  • Memory usage: من 180MB لـ 18MB.
  • Scroll FPS: من 22 إلى 60 ثابت.
  • Long Task أطول: من 1800ms لـ 12ms.

الافتراض إن المتصفح Chrome 120 على جهاز متوسط (8GB RAM، Apple M1). على أجهزة أضعف الفرق بيكبر؛ على Intel i3 قديم، التحسّن قاسيته 60–80×.

لوحة قياس أداء تعرض أرقام زمن الاستجابة وعدد العمليات قبل وبعد تطبيق Virtualization على قائمة React

الـ Trade-offs اللي لازم تعرفها قبل ما تنفّذ

Virtualization بتكسب أداء، بتدفع 4 تكاليف صريحة:

  1. الـ scrollbar مش بيمثّل الواقع بدقة لو ارتفاعات العناصر متفاوتة جدًا. الحل: measureElement لكن بيكلّفك reflow صغير على كل عنصر جديد يدخل الشاشة.
  2. Search/Find داخل الصفحة (Ctrl+F) مش هيلاقي العناصر اللي مش في DOM. لو ده requirement أساسي لمستخدمينك، Virtualization مش حلّك المباشر.
  3. Accessibility: screen readers بتعتمد على الـ DOM. لازم تحط role="grid"، aria-rowcount، و aria-rowindex على كل صف، علشان أدوات المساعدة تعرف الحجم الحقيقي للقائمة.
  4. الـ CSS بيتعقّد: أي عنصر فيه position: sticky أو animations معقدة هيحتاج تعديل، لأن العناصر بتتحرّك بـ transform: translateY بدل ما تقعد مكانها.

متى لا تستخدم Virtualization

القاعدة العملية: تحت 200 عنصر مش محتاج Virtualization أصلًا، وممكن تضيف تعقيد بدون فايدة. ركّز على البدائل دي:

  • قوائم أقل من 200 عنصر: استخدم pagination أو infinite scroll عادي. التحسّن مش هيظهر للمستخدم.
  • عناصر معقدة جدًا داخل كل صف (charts كاملة، فيديوهات): الـ Virtualization مش هتحلّ بطء العنصر نفسه. الحل: قلّل تعقيد العنصر أولًا.
  • SEO-critical content: محرّكات البحث بتشوف الـ DOM المرسوم. لو محتواك لازم يتفهرس، Virtualization هيخفي 99% منه عن Googlebot.
  • طباعة الصفحة: المستخدم لما يطبع، هيطلع له الـ 20 عنصر اللي في الـ DOM بس. لو فيه print view، اعمل توجل يعطّل الـ Virtualization مؤقتًا.

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

افتح أكبر قائمة في تطبيقك دلوقتي. شغّل Chrome DevTools → Performance → سجّل scroll لمدة 5 ثواني. لو الـ FPS تحت 50 أو فيه Long Tasks فوق 50ms، أنت محتاج Virtualization. ابدأ بـ TanStack Virtual، طبّق المثال فوق على أبسط جدول عندك، وقيس قبل وبعد بنفس الـ DevTools. لو الفرق أقل من 5×، المشكلة مش في عدد العناصر، هي في تعقيد الصف نفسه.

مصادر

  • TanStack Virtual Documentation — tanstack.com/virtual/latest
  • React docs على Render & Commit — react.dev/learn/render-and-commit
  • web.dev — Optimize Long Tasks — web.dev/articles/optimize-long-tasks
  • Chrome DevTools Performance Reference — developer.chrome.com/docs/devtools/performance
  • MDN — Web Performance: Layout & Paint — developer.mozilla.org/Web/Performance

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

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

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