القوائم والشروط في React — دليل شامل 2026
دليل عملي مفصل للقوائم والشروط في React — map, filter, key، والتصيير الشرطي، مع تمارين وحلول
في المقال السابق، تعلمت useEffect وإدارة التأثيرات الجانبية. الآن سنتعلم القوائم (Lists) و الشروط (Conditionals) — وهي الطريقة التي نعرض بها البيانات ديناميكياً في React.
في هذا الدليل العملي، سنأخذك خطوة بخطوة لفهم كيفية عرض القوائم والشروط في React، مع تمارين وحلول.
عرض القوائم
1. الطريقة الأساسية — map
function FruitList() {
const fruits = ["تفاح", "موز", "برتقال"];
return (
<ul>
{fruits.map((fruit) => (
<li key={fruit}>{fruit}</li>
))}
</ul>
);
}
شرح:
map: تُحوّل كل عنصر في المصفوفة إلى JSX.key: معرّف فريد لكل عنصر (مهم للأداء).
2. قائمة كائنات
interface User {
id: number;
name: string;
email: string;
}
function UserList() {
const users: User[] = [
{ id: 1, name: "أحمد", email: "[email protected]" },
{ id: 2, name: "محمد", email: "[email protected]" },
{ id: 3, name: "علي", email: "[email protected]" },
];
return (
<ul>
{users.map((user) => (
<li key={user.id}>
<strong>{user.name}</strong> - {user.email}
</li>
))}
</ul>
);
}
3. استخدام مكوّن منفصل
interface UserProps {
user: User;
}
function UserItem({ user }: UserProps) {
return (
<li>
<strong>{user.name}</strong> - {user.email}
</li>
);
}
function UserList() {
const users: User[] = [...];
return (
<ul>
{users.map((user) => (
<UserItem key={user.id} user={user} />
))}
</ul>
);
}
أهمية key
key هو معرّف فريد لكل عنصر في القائمة.
لماذا key مهم؟
- الأداء: React يستخدمه لمعرفة العناصر التي تغيرت.
- الحالة: يحافظ على state العناصر.
- التحذيرات: بدون
key، React يعطي تحذيراً.
❌ طرق خاطئة:
// ❌ بدون key:
{items.map((item) => <li>{item}</li>)}
// ❌ استخدام index (خطر):
{items.map((item, index) => <li key={index}>{item}</li>)}
⚠️ لماذا index خطير؟
- عند إضافة/حذف عنصر، تتغير الـ indices.
- React قد يعيد استخدام العناصر بشكل خاطئ.
- يفقد state العنصر.
✅ الطريقة الصحيحة:
// ✅ باستخدام id فريد:
{items.map((item) => <li key={item.id}>{item.name}</li>)}
// ✅ باستخدام قيمة فريدة:
{fruits.map((fruit) => <li key={fruit}>{fruit}</li>)}
الشروط في JSX
1. if خارج JSX
function Greeting({ isLoggedIn }: { isLoggedIn: boolean }) {
if (isLoggedIn) {
return <h1>مرحباً بك!</h1>;
}
return <h1>سجّل الدخول</h1>;
}
2. Ternary Operator (? :)
function Greeting({ isLoggedIn }: { isLoggedIn: boolean }) {
return (
<h1>{isLoggedIn ? "مرحباً بك!" : "سجّل الدخول"}</h1>
);
}
الاستخدام: خياران فقط.
3. && — العرض الشرطي
function Inbox({ messages }: { messages: string[] }) {
return (
<div>
<h1>صندوق الوارد</h1>
{messages.length > 0 && (
<p>لديك {messages.length} رسالة</p>
)}
{messages.length === 0 && <p>لا توجد رسائل</p>}
</div>
);
}
⚠️ تحذير: إذا كانت القيمة 0، ستُعرض 0 في JSX!
// ❌ خطأ (يعرض "0" إذا كان length === 0):
{messages.length && <p>...</p>}
// ✅ صحيح:
{messages.length > 0 && <p>...</p>}
4. if-else if-else — حالات متعددة
function StatusBadge({ status }: { status: "pending" | "approved" | "rejected" }) {
if (status === "pending") {
return <span className="yellow">⏳ قيد المراجعة</span>;
}
if (status === "approved") {
return <span className="green">✅ مقبول</span>;
}
return <span className="red">❌ مرفوض</span>;
}
5. switch — حالات كثيرة
function Icon({ type }: { type: string }) {
switch (type) {
case "user":
return <span>👤</span>;
case "email":
return <span>📧</span>;
case "phone":
return <span>📱</span>;
default:
return <span>❓</span>;
}
}
التصيير المتقدم
1. تصفية القائمة
function ProductList({ products, showInStock }: { products: Product[]; showInStock: boolean }) {
const filtered = showInStock
? products.filter((p) => p.inStock)
: products;
return (
<ul>
{filtered.map((p) => (
<li key={p.id}>{p.name}</li>
))}
</ul>
);
}
2. ترتيب القائمة
const sorted = [...products].sort((a, b) => a.price - b.price);
3. البحث
const [query, setQuery] = useState("");
const filtered = products.filter((p) =>
p.name.toLowerCase().includes(query.toLowerCase())
);
4. تجميع القائمة
const grouped = products.reduce<Record<string, Product[]>>((acc, p) => {
const category = p.category;
if (!acc[category]) acc[category] = [];
acc[category].push(p);
return acc;
}, {});
مثال عملي: قائمة مهام كاملة
interface Todo {
id: number;
text: string;
completed: boolean;
}
function TodoApp() {
const [todos, setTodos] = useState<Todo[]>([
{ id: 1, text: "تعلم React", completed: true },
{ id: 2, text: "بناء مشروع", completed: false },
{ id: 3, text: "نشر الموقع", completed: false },
]);
const [filter, setFilter] = useState<"all" | "active" | "completed">("all");
const filteredTodos = todos.filter((todo) => {
if (filter === "active") return !todo.completed;
if (filter === "completed") return todo.completed;
return true;
});
return (
<div className="todo-app">
<h1>📝 قائمة المهام</h1>
<div className="filters">
<button onClick={() => setFilter("all")}>الكل</button>
<button onClick={() => setFilter("active")}>النشطة</button>
<button onClick={() => setFilter("completed")}>المكتملة</button>
</div>
{filteredTodos.length === 0 ? (
<p className="empty">لا توجد مهام</p>
) : (
<ul>
{filteredTodos.map((todo) => (
<li key={todo.id} className={todo.completed ? "done" : ""}>
<input
type="checkbox"
checked={todo.completed}
onChange={() =>
setTodos(
todos.map((t) =>
t.id === todo.id ? { ...t, completed: !t.completed } : t
)
)
}
/>
<span>{todo.text}</span>
</li>
))}
</ul>
)}
</div>
);
}
مثال عملي: قائمة منتجات
interface Product {
id: number;
name: string;
price: number;
image: string;
inStock: boolean;
}
function ProductGrid() {
const products: Product[] = [
{ id: 1, name: "لابتوب", price: 5000, image: "...", inStock: true },
{ id: 2, name: "هاتف", price: 2000, image: "...", inStock: true },
{ id: 3, name: "تابلت", price: 1500, image: "...", inStock: false },
];
return (
<div className="grid">
{products.map((product) => (
<div key={product.id} className="product-card">
<img src={product.image} alt={product.name} />
<h3>{product.name}</h3>
<p>{product.price} $</p>
{product.inStock ? (
<span className="in-stock">✅ متوفر</span>
) : (
<span className="out-of-stock">❌ غير متوفر</span>
)}
</div>
))}
</div>
);
}
عرض البيانات الشرطية المتقدمة
1. حالات API (Loading/Error/Success)
type State =
| { status: "idle" }
| { status: "loading" }
| { status: "success"; data: string[] }
| { status: "error"; message: string };
function DataView() {
const [state, setState] = useState<State>({ status: "idle" });
if (state.status === "loading") return <p>جاري التحميل...</p>;
if (state.status === "error") return <p>خطأ: {state.message}</p>;
if (state.status === "success") {
return (
<ul>
{state.data.map((item, i) => (
<li key={i}>{item}</li>
))}
</ul>
);
}
return <button onClick={() => setState({ status: "loading" })}>ابدأ</button>;
}
2. عرض شرطي متداخل
function UserProfile({ user }: { user: User | null }) {
if (!user) return <p>لم يتم تسجيل الدخول</p>;
return (
<div>
<h2>{user.name}</h2>
{user.isAdmin && <span className="badge">👑 مدير</span>}
{user.posts.length > 0 ? (
<ul>
{user.posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
) : (
<p>لا توجد مقالات</p>
)}
</div>
);
}
تمارين عملية
تمرين 1: قائمة أسماء
اعرض مصفوفة أسماء في قائمة.
الحل:
function Names() {
const names = ["أحمد", "محمد", "علي"];
return <ul>{names.map((n) => <li key={n}>{n}</li>)}</ul>;
}
تمرين 2: قائمة أرقام مع شرط
اعرض الأرقام الزوجية فقط.
الحل:
function EvenNumbers() {
const nums = [1, 2, 3, 4, 5, 6];
const evens = nums.filter((n) => n % 2 === 0);
return <ul>{evens.map((n) => <li key={n}>{n}</li>)}</ul>;
}
تمرين 3: عرض شرطي
اعرض "مرحباً" إذا كان isLoggedIn صحيحاً، وإلا "سجّل الدخول".
الحل:
function Greeting({ isLoggedIn }: { isLoggedIn: boolean }) {
return <h1>{isLoggedIn ? "مرحباً" : "سجّل الدخول"}</h1>;
}
تمرين 4: قائمة مهام مع تصفية
اعرض المهام النشطة فقط.
الحل:
function ActiveTodos() {
const todos = [
{ id: 1, text: "مهمة 1", done: true },
{ id: 2, text: "مهمة 2", done: false },
{ id: 3, text: "مهمة 3", done: false },
];
const active = todos.filter((t) => !t.done);
return <ul>{active.map((t) => <li key={t.id}>{t.text}</li>)}</ul>;
}
تمرين 5: حالة فارغة
اعرض "لا توجد بيانات" إذا كانت القائمة فارغة.
الحل:
function EmptyList({ items }: { items: string[] }) {
if (items.length === 0) return <p>لا توجد بيانات</p>;
return <ul>{items.map((i) => <li key={i}>{i}</li>)}</ul>;
}
تمرين 6: بحث في القائمة
اعرض فقط المنتجات التي تحتوي على نص البحث.
الحل:
function SearchProducts() {
const [query, setQuery] = useState("");
const products = ["لابتوب", "هاتف", "تابلت", "سماعات"];
const filtered = products.filter((p) =>
p.toLowerCase().includes(query.toLowerCase())
);
return (
<div>
<input value={query} onChange={(e) => setQuery(e.target.value)} />
<ul>{filtered.map((p) => <li key={p}>{p}</li>)}</ul>
</div>
);
}
تمرين 7: ترتيب القائمة
اعرض الأرقام مرتبة تصاعدياً.
الحل:
function SortedNumbers() {
const nums = [5, 2, 8, 1, 9, 3];
const sorted = [...nums].sort((a, b) => a - b);
return <ul>{sorted.map((n) => <li key={n}>{n}</li>)}</ul>;
}
تمرين 8: جدول مستخدمين
اعرض جدول مستخدمين مع حالاتهم.
الحل:
interface User {
id: number;
name: string;
active: boolean;
}
function UsersTable() {
const users: User[] = [
{ id: 1, name: "أحمد", active: true },
{ id: 2, name: "محمد", active: false },
{ id: 3, name: "علي", active: true },
];
return (
<table>
<thead>
<tr>
<th>الاسم</th>
<th>الحالة</th>
</tr>
</thead>
<tbody>
{users.map((user) => (
<tr key={user.id}>
<td>{user.name}</td>
<td>{user.active ? "✅ نشط" : "❌ غير نشط"}</td>
</tr>
))}
</tbody>
</table>
);
}
حل المشاكل الشائعة
🔴 المشكلة 1: Warning: Each child in a list should have a unique "key" prop
السبب: عدم وجود key في القائمة.
الحل: أضف key فريد.
🔴 المشكلة 2: Objects are not valid as a React child
السبب: عرض كائن مباشرة.
الحل: اعرض خاصية من الكائن.
🔴 المشكلة 3: عرض 0 بدلاً من لا شيء
السبب: استخدام && مع رقم.
الحل:
// ❌
{items.length && <p>...</p>}
// ✅
{items.length > 0 && <p>...</p>}
🔴 المشكلة 4: Cannot read property 'map' of undefined
السبب: القيمة غير معرّفة.
الحل:
{items?.map(...) || <p>لا توجد بيانات</p>}
جدول طرق القوائم
| الطريقة | الوظيفة |
|---|---|
map | تحويل كل عنصر |
filter | تصفية العناصر |
sort | ترتيب |
reduce | تجميع |
slice | جزء من القائمة |
find | إيجاد عنصر |
قائمة تحقق نهائية
| المهمة | الحالة |
|---|---|
| عرض القوائم باستخدام map | ⬜ |
| فهم أهمية key | ⬜ |
| الشروط باستخدام ? : | ⬜ |
| الشروط باستخدام && | ⬜ |
| تصفية وترتيب القوائم | ⬜ |
| الحالات المعقدة (Loading/Error) | ⬜ |
| حل التمارين الثمانية | ⬜ |
ماذا بعد هذا المقال؟
الآن بعد أن أتقنت القوائم والشروط، أنت جاهز للمقال التالي:
- React Router — التنقل بين الصفحات.
- Context API — إدارة الحالة العامة.
- مشروع متكامل — تطبيق كامل.
الخلاصة
في هذا المقال، تعلمت:
- ✅ عرض القوائم باستخدام
map. - ✅ أهمية
keyولماذاindexخطر. - ✅ الشروط في JSX (
? :,&&,if). - ✅ تصفية وترتيب القوائم.
- ✅ الحالات المعقدة (Loading/Error/Success).
- ✅ حل 8 تمارين عملية.
تذكر: القوائم والشروط هي أساس كل تطبيق ديناميكي. أتقنها جيداً.
هل أتقنت القوائم والشروط؟ شاركنا في التعليقات!
useEffect في React — دليل شامل للتأثيرات الجانبية 2026
React Router — التنقل بين الصفحات في React 2026
📚 مقالات ذات صلة
مشروع React متكامل — تطبيق متجر إلكتروني 2026
مشروع عملي شامل لبناء تطبيق متجر إلكتروني بـ React و TypeScript — مع السلة، البحث، التصفية، والحفظ التلقائي
Context API في React — إدارة الحالة العامة 2026
دليل عملي مفصل لـ Context API في React — إنشاء Context، Provider، useContext، مع تمارين وحلول
React Router — التنقل بين الصفحات في React 2026
دليل عملي مفصل لـ React Router — التنقل، المسارات، الروابط، والمعاملات، مع تمارين وحلول