| المحور الهندسي | الآلية البرمجية في React | الأثر المباشر على الأداء وتجربة المستخدم (UX) |
|---|---|---|
| هيكل حالة التحديد Selected State | استخدام Set بدلاً من Array لتخزين المعرفات المحددة (Set of IDs) | عمليات إضافة وحذف وفحص وجود العناصر بأسلوب خارق السعة بأداء O(1) |
| تحديد الكل Select All | مطابقة عدد المعرفات المحددة بإجمالي عناصر القائمة المفلترة | إمكانية تحديد كافة الدروس أو إلغائها بضغطة زر واحدة بسلاسة |
| الإجراءات الجماعية Bulk Actions | تطبيق عملية معالجة موحدة (حذف، تغيير حالة، تصدير) على مجموعة معرفات | تقليل الاتصالات بالسيرفر وتوفير وقت كبير للمستخدم |
| المنطق البولياني المزدوج Indeterminate State | حالة يكون فيها صندوق الاختيار الرئيسي محدداً جزئياً (Checkbox Indeterminate) | إعطاء إشارة بصرية دقيقة بأن بعض العناصر محددة وليست كلها |
عند التعامل مع لوحات الإدارة أو القوائم التفاعلية، يحتاج المطور لإتاحة الفرصة للمستخدم لاختيار أكثر من عنصر في الوقت نفسه للقيام بعمليات جماعية مثل: (حذف 10 دروس دفعة واحدة، تغيير حالة مجموعة طلاب، أو تصدير ملفات مختارة).
الملاحظة الهندسية الأهم هنا هي كيفية تمثيل حالة التحديد داخل الـ State بأفضل أداء وبأقل مساحة ذاكرة.
الخطأ الشائع هو تخزين المזהات المحددة داخل مصفوفة عادية []. البحث داخل المصفوفة للتحقق هل العنصر محدد أم لا يحتاج دالة .includes() التي تستغرق وقتاً زمنيّاً خطيّاً $O(N)$.الخيار الأفضل هندسياً هو استخدام Set لأن دالة .has() تبحث في زمن ثابت $O(1)$ مهما بلغت كمية العناصر!
| 1 | // استخدام Set لتخزين معرّفات العناصر المحددة |
| 2 | const [selectedIds, setSelectedIds] = useState(new Set()); |
| 3 | |
| 4 | // دالة التحديد أو إلغاء التحديد للسطر الواحد |
| 5 | const toggleSelect = (id) => { |
| 6 | setSelectedIds((prev) => { |
| 7 | const next = new Set(prev); |
| 8 | if (next.has(id)) { |
| 9 | next.delete(id); // إلغاء التحديد لو كان موجوداً |
| 10 | } else { |
| 11 | next.add(id); // إضافة المعرّف |
| 12 | } |
| 13 | return next; |
| 14 | }); |
| 15 | }; |
لتطوير زر "تحديد الكل"، نقارن عدد العناصر المحددة بإجمالي عناصر القائمة الحالية.
| 1 | // فحص هل جميع العناصر محددة حالياً؟ |
| 2 | const isAllSelected = courses.length > 0 && selectedIds.size === courses.length; |
| 3 | |
| 4 | // دالة تحديد الكل أو تبديلها |
| 5 | const toggleSelectAll = () => { |
| 6 | if (isAllSelected) { |
| 7 | setSelectedIds(new Set()); // تصفير التحديد بالكامل |
| 8 | } else { |
| 9 | const allIds = courses.map((course) => course.id); |
| 10 | setSelectedIds(new Set(allIds)); // إضافة كافة المعرفات |
| 11 | } |
| 12 | }; |
عندما يضغط المستخدم على زر "حذف العناصر المحددة"، نمرر كائن الـ Set أو نحوله لمصفوفة للتعامل مع السيرفر أو الـ State الرئيسية.
| 1 | const handleBulkDelete = () => { |
| 2 | // تصفية القائمة وحذف كل عنصر موجود معرّفه داخل selectedIds |
| 3 | setCourses((prev) => prev.filter((course) => !selectedIds.has(course.id))); |
| 4 | |
| 5 | // تصفية التحديد بعد انتهاء العملية |
| 6 | setSelectedIds(new Set()); |
| 7 | }; |
⚠️ تحذير
تذكر دائماً أن دالة selectedIds.add(id) تعدل على نفس الكائن داخل الذاكرة (In-place Mutation). لو كتبت:
| 1 | // خطأ: ريأكت لن تشعر بالتغير لأن المرجع في الذاكرة هو نفسه! |
| 2 | selectedIds.add(id); |
| 3 | setSelectedIds(selectedIds); |
يجب عليك دائماً إنتاج كائن Set جديد كلياً ليصبح المرجع مختلفاً وتكتشف React التغيير وتطلق إعادة الرندرة فوراً:
| 1 | // صح: إنشـاء نسخة جديدة من Set |
| 2 | setSelectedIds(new Set(selectedIds.add(id))); |