const latestBooks = data?.slice(0, 5);
// استيراد Hooks من React
// useEffect = لتنفيذ كود عند تحميل الكومبوننت أو تغير القيم
// useState = لإنشاء state محلي (غير مستخدم هنا فعلياً لكنه مستورد)
import { useEffect, useState } from "react";
// استيراد Hooks من Redux
// useDispatch = لإرسال actions إلى الـ store
// useSelector = لقراءة البيانات من Redux store
import { useDispatch, useSelector } from "react-redux";
// useParams = لقراءة القيم من رابط الصفحة (URL)
// هنا نستخدمه للحصول على id التصنيف
import { useParams } from "react-router-dom";
// كومبوننت لعرض بطاقة كتاب واحدة
import Book from "../../components/Book/Book";
// api instance (axios) — غير مستخدم هنا حالياً
import api from "../../api";
// Action لجلب جميع الكتب من السيرفر وتخزينها في Redux
import { getAllBooks } from "../../store/booksSlice";
function ArchivePage() {
// قراءة id التصنيف من الرابط
// مثال: /category/3 → id = 3
const { id } = useParams();
// إنشاء dispatch لإرسال actions إلى Redux
const dispatch = useDispatch();
// قراءة البيانات من Redux store
// state.products = اسم slice داخل store
// data = قائمة الكتب
// isLoading = حالة التحميل
// error = في حال حدوث خطأ
const { data, isLoading, error } = useSelector((state) => state.products);
// فلترة الكتب حسب التصنيف الحالي
// categories عبارة عن Array لذلك نستخدم some()
// some() تعني: هل يحتوي الكتاب على هذا التصنيف؟
const filteredBooks = data.filter((book) =>
book.categories?.some((cat) => cat.id === Number(id))
);
// طباعة النتائج في الكونسول للمراقبة
console.log(filteredBooks)
// useEffect يعمل عند تحميل الصفحة لأول مرة
useEffect(() => {
// إذا كانت Redux فارغة (بعد refresh مثلاً)
// نقوم بجلب الكتب من السيرفر مرة أخرى
if (!data.length) dispatch(getAllBooks());
}, []); // [] = يعمل مرة واحدة فقط عند تحميل الصفحة
return (
<div>
{/* عنوان الصفحة (فارغ حالياً) */}
<h1 className="text-center"></h1>
<div className="container">
{/* شبكة عرض الكتب */}
<div className="row row-cols-lg-5">
{
// عرض الكتب بعد الفلترة
// map() تمر على كل كتاب وتعرضه
filteredBooks?.map((book) => (
<Book book={book} />
))
}
</div>
</div>
</div>
)
}
export default ArchivePage;
JavaScript🧠 أولاً: السطر الكامل
const filteredBooks = data.filter((book) =>
book.categories?.some((cat) => cat.id === Number(id)
);JavaScript🎯 ماذا نريد أن نفعل؟
نريد:
اختيار الكتب التي تنتمي للتصنيف الحالي فقط.
🧩 لنفهم شكل البيانات أولاً
شكل الكتب داخل data
data = [
{
id: 1,
name: "Book A",
categories: [
{ id: 2, name: "Programming" },
{ id: 5, name: "Web" }
]
},
{
id: 2,
name: "Book B",
categories: [
{ id: 3, name: "Design" }
]
}
]JavaScript🧩 قيمة id من الرابط
لو الرابط:
/category/2JavaScriptفإن:
id = "2" // stringJavaScript🧠 لذلك نحوله إلى رقم
Number(id) = 2JavaScript🚀 الآن نشرح السطر جزء جزء
✅ الجزء 1 — filter()
data.filter(...)JavaScriptماذا يفعل؟
يمر على كل كتاب ويقرر:
👉 هل نحتفظ به أم نحذفه؟
القاعدة:
إذا رجع الشرط:
true → يبقى الكتاب
false → يتم حذفهJavaScript🧩 مثال بسيط
[1,2,3,4].filter(num => num > 2)JavaScriptالنتيجة:
[3,4]JavaScript🧠 إذن:
filter = “فلترة العناصر”
✅ الجزء 2 — book.categories
هذا يعني:
👉 الوصول إلى تصنيفات الكتاب.
لماذا استخدمنا ?.
book.categories?.some(...)JavaScriptلأن بعض الكتب قد لا تحتوي على تصنيفات.
بدون ?. سيحدث crash.
🧠 إذن:
?. = optional chainingJavaScriptتعني:
إذا لم يوجد categories لا تنفذ الكود.
✅ الجزء 3 — some()
هذا هو الجزء الأهم.
ماذا يفعل some ؟
يمر على Array ويجيب:
👉 هل يوجد عنصر واحد على الأقل يحقق الشرط؟
يرجع فقط:
true أو falseJavaScript🧩 مثال بسيط
[1,2,3].some(n => n === 2)JavaScriptالنتيجة:
trueJavaScript[1,2,3].some(n => n === 5)JavaScriptالنتيجة:
falseJavaScript🧠 إذن:
some = “هل يوجد عنصر مطابق؟”
✅ الجزء 4 — cat.id === Number(id)
هذا هو الشرط.
يعني:
👉 هل ID التصنيف داخل الكتاب يساوي ID التصنيف من الرابط؟
🎯 الآن نربط كل شيء معاً
🧠 كيف يعمل الكود فعلياً؟
React يقوم بالآتي:
الخطوة 1
يمر على كل كتاب:
book1
book2
book3JavaScriptالخطوة 2
لكل كتاب:
يدخل إلى categories
الخطوة 3
يفحص:
هل يوجد تصنيف id = 2 ؟
الخطوة 4
إذا نعم:
some() → trueJavaScript➡️ filter يحتفظ بالكتاب.
إذا لا:
some() → falseJavaScript➡️ filter يحذف الكتاب.
🧩 مثال عملي كامل
البيانات
id = 2Book A categories = [2,5]
Book B categories = [3]JavaScriptالنتيجة
Book A → يحتوي 2 → يظهر
Book B → لا يحتوي → يُحذفJavaScript🏆 الناتج النهائي
filteredBooks =
[
Book A
]JavaScript🧠 لماذا استخدمنا some وليس filter؟
لأننا لا نريد كل التصنيفات.
نريد فقط:
👉 معرفة هل يوجد واحد مطابق.
⭐ الفرق بين filter و some
| الدالة | ترجع |
|---|---|
| filter | Array جديد |
| some | true / false |
💡 الصيغة البشرية للكود
يمكن قراءته هكذا:
خذ جميع الكتب التي تحتوي على تصنيف id يساوي id الموجود في الرابط.
🏆 الخلاصة النهائية
السطر يفعل 4 أشياء:
1️⃣ يمر على الكتب
2️⃣ يدخل إلى تصنيفات كل كتاب
3️⃣ يبحث عن تصنيف مطابق
4️⃣ يحتفظ بالكتاب إذا وجده