لو عندك جدول فيه 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.
افهم 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.
npm install @tanstack/react-virtualكود قائمة 10 آلاف عنصر، قابل للنسخ مباشرة: