← السابق المستوى 4 - الدرس 2 من 12

🧩 Components و JSX المتقدم: بناء واجهات معقدة بطريقة احترافية

تعلم كيفية تقسيم التطبيقات الكبيرة إلى مكونات صغيرة وقابلة لإعادة الاستخدام مع أفضل الممارسات

تقدمك في المستوى الرابع 16%

🎯 ما ستتعلمه في هذا الدرس

  • فهم أنواع Components ومتى تستخدم كل نوع
  • تمرير البيانات بين المكونات باستخدام Props بشكل احترافي
  • استخدام Composition لبناء تطبيقات معقدة من مكونات بسيطة
  • استخدام Children لإنشاء مكونات قابلة للتخصيص
  • تجنب الأخطاء الشائعة التي يقع فيها 90% من المبتدئين

🧩 ما هو Component ولماذا يُعتبر "السر" وراء React؟

Component (المكون) هو قطعة مستقلة وقابلة لإعادة الاستخدام من واجهة المستخدم. يمكن أن يكون زر، نموذج، قائمة، أو أي عنصر واجهة مستخدم آخر. لكن لماذا هذا المفهوم مهم جداً؟

في بداية تعلمي للبرمجة، كنت أبني موقع متجر إلكتروني باستخدام HTML وCSS وJavaScript العادي. المشكلة؟ كل صفحة كانت ملفاً منفصلاً، وكل زر "أضف للسلة" كان يتكرر في 20 مكاناً مختلفاً. عندما أردت تغيير لون الزر، اضطررت لتعديل 20 ملفاً! استغرقت 3 ساعات لتعديل شيء بسيط.

مع React، تكتب مكون Button مرة واحدة، وتستخدمه في 100 مكان. تغيير لون الزر؟ تعديل في ملف واحد فقط — والتغيير ينطبق على كل مكان. هذا هو قوة المكونات.

فوائد المكونات في المشاريع الحقيقية:

📝 أنواع Components — Function vs Class

1. Function Component (الحديث والمستحسن — 95% من المشاريع الجديدة)

Function Component هو ببساطة دالة JavaScript تُرجع JSX. هذا هو النمط الحديث والموصى به من Facebook (Meta) منذ 2019. السبب؟ أبسط، أخف، ويدعم Hooks بشكل كامل.

// Greeting.js — Function Component بسيط function Greeting(props) { return <h1>مرحباً {props.name}!</h1>; } // ✅ الطريقة الأفضل: Destructuring // بدلاً من props.name، نفك الـ Props مباشرة function GreetingBetter({ name, age }) { return ( <div className="greeting-card"> <h1>مرحباً {name}!</h1> <p>عمرك: {age} سنة</p> </div> ); } // استخدام المكونات <Greeting name="أحمد" /> <GreetingBetter name="فاطمة" age={25} />
💡 نصيحة من الخبرة: استخدم دائماً Destructuring في Props. بدلاً من props.name و props.age، استخدم { name, age }. هذا يجعل الكود أقصر وأسهل للقراءة — خاصة عندما يكون لديك 10+ Props.

2. Class Component (القديم — تعرفه فقط للصيانة)

Class Components كانت الطريقة الوحيدة لإدارة State قبل 2019. لا تُنصح بها للمشاريع الجديدة، لكنك قد تصادفها في مشاريع قديمة تحتاج صيانة.

import React, { Component } from 'react'; class Greeting extends Component { render() { return <h1>مرحباً {this.props.name}!</h1>; } } // ❌ لا تستخدم هذا في مشاريع جديدة! // ✅ استخدم Function Component مع useState بدلاً منه
⚠️ خطأ شائع: بعض المبتدئين يتعلمون Class Components أولاً لأنها تظهر في دورات قديمة. هذا خطأ! ابدأ بـ Function Components مباشرة — كل المشاريع الحديثة تستخدمها.

🎨 Props — نقل البيانات بين المكونات بشكل احترافي

Props (اختصار Properties) هي بيانات تُمرر من مكون أب (Parent) لمكون ابن (Child). تشبه معاملات الدالة في JavaScript. لكن هناك قاعدة ذهبية: Props قراءة فقط (Read-only).

لماذا Props ثابتة؟ لأن React تبني على مفهوم "One-way Data Flow" (تدفق بيانات باتجاه واحد). البيانات تتدفق من الأعلى للأسفل، مثل شلال. هذا يجعل تتبع الأخطاء سهلاً — إذا ظهرت بيانات خاطئة، تعرف مصدرها مباشرة من المكون الأب.

مثال واقعي: بطاقة مستخدم في تطبيق تواصل اجتماعي

// UserCard.js — مكون يستقبل عدة Props function UserCard({ name, age, email, isActive, avatar, onMessage }) { // Props: بيانات تأتي من الخارج (ثابتة) return ( <div className={`user-card ${isActive ? 'active' : 'inactive'}`}> <img src={avatar} alt={`صورة ${name}`} className="avatar" /> <div className="user-info"> <h3>{name}</h3> <p>العمر: {age} سنة</p> <p>البريد: {email}</p> <span className={`status-badge ${isActive ? 'online' : 'offline'}`}> {isActive ? '🟢 نشط الآن' : '🔴 غير نشط'} </span> </div> <button onClick={onMessage} className="msg-btn"> 💬 رسالة </button> </div> ); } // استخدام المكون مع بيانات مختلفة <UserCard name="أحمد محمد" age={28} email="ahmed@example.com" isActive={true} avatar="https://example.com/ahmed.jpg" onMessage={() => alert('فتح دردشة مع أحمد')} /> <UserCard name="فاطمة علي" age={24} email="fatima@example.com" isActive={false} avatar="https://example.com/fatima.jpg" onMessage={() => alert('فتح دردشة مع فاطمة')} />
💡 نصيحة احترافية: عند تمرير دوال (Functions) كـ Props، استخدم دائماً onSomething كاسم — مثل onClick، onMessage، onDelete. هذا يجعل الكود أكثر وضوحاً ويتبع اتفاقية React القياسية.

🎯 Composition — بناء تطبيقات معقدة من مكونات بسيطة

Composition (التركيب) هو المفهوم الأساسي في React: بناء واجهات معقدة من مكونات بسيطة صغيرة. تخيل بناء منزل — لا تبدأ بمنزل كامل، بل تبدأ بلبنات (طوب، أبواب، نوافذ) ثم تركبها معاً.

في مشروع حقيقي عملته (لوحة تحكم لمتجر إلكتروني)، قسمت الواجهة إلى 12 مكوناً:

النتيجة؟ كل مكون 80-150 سطر، سهل الفهم والتعديل. لو أردت تغيير تصميم StatsCard، عدلت ملف واحد — والتغيير انطبق على 4 أماكن.

مثال: هيكل تطبيق كامل

// App.js — المكون الرئيسي يركب كل شيء function App() { return ( <div className="app-container"> <Header title="لوحة التحكم" user={currentUser} /> <div className="main-layout"> <Sidebar activeItem="dashboard" /> <main className="content"> <StatsRow /> <div className="charts-grid"> <SalesChart period="month" /> <UsersChart period="week" /> </div> <RecentOrders limit={5} /> </main> </div> <Footer version="2.1.0" /> </div> ); } // كل مكون مسؤول عن جزء محدد — سهل الفهم والصيانة function Header({ title, user }) { return ( <header className="app-header"> <h1>{title}</h1> <div className="user-menu"> <img src={user.avatar} alt={user.name} /> <span>{user.name}</span> </div> </header> ); } function Sidebar({ activeItem }) { const items = [ { id: 'dashboard', label: 'الرئيسية', icon: '🏠' }, { id: 'products', label: 'المنتجات', icon: '📦' }, { id: 'orders', label: 'الطلبات', icon: '🛒' }, { id: 'users', label: 'المستخدمين', icon: '👥' }, ]; return ( <aside className="sidebar"> {items.map(item => ( <a key={item.id} href={`#${item.id}`} className={activeItem === item.id ? 'active' : ''} > {item.icon} {item.label} </a> ))} </aside> ); }

⚡ Children — إنشاء مكونات قابلة للتخصيص

Children هي خاصية خاصة في React. أي محتوى تضعه بين وسمي المكون (<Card>...</Card>) يصبح props.children. هذا يسمح بإنشاء "مكونات غلاف" (Wrapper Components) قابلة لإعادة الاستخدام مع محتوى مختلف.

من تجربتي: في مشروع لوحة تحكم، احتجت بطاقات (Cards) بتصاميم مختلفة — بطاقة إحصائيات، بطاقة رسوم بيانية، بطاقة تنبيهات. بدلاً من إنشاء 3 مكونات منفصلة، أنشأت مكون Card واحداً يستخدم Children:

// Card.js — مكون غلاف قابل لإعادة الاستخدام function Card({ children, title, variant = 'default', footer }) { // variant: 'default' | 'stats' | 'chart' | 'alert' return ( <div className={`card card-${variant}`}> {title && ( <div className="card-header"> <h3>{title}</h3> </div> )} <div className="card-body"> {children} </div> {footer && ( <div className="card-footer"> {footer} </div> )} </div> ); } // استخدام 1: بطاقة إحصائيات <Card title="إجمالي المبيعات" variant="stats"> <div className="stat-value">₤ 125,000</div> <div className="stat-change positive">+12% عن الشهر الماضي</div> </Card> // استخدام 2: بطاقة رسوم بيانية <Card title="مبيعات الشهر" variant="chart"> <BarChart data={salesData} /> </Card> // استخدام 3: بطاقة تنبيه مع Footer <Card title="تنبيه" variant="alert" footer={<button>فهمت</button>} > <p>هناك 5 طلبات بحاجة للمراجعة العاجلة.</p> </Card>
🎯 نصيحة احترافية: استخدم variant لتغيير التصميم بدون تغيير المنطق. هذا يجعل مكون Card مرناً جداً — يمكن استخدامه في 10 سياقات مختلفة بنفس الكود الأساسي.

💡 أفضل الممارسات من مشاريع حقيقية

1. اسم المكون يبدأ بحرف كبير

React تفرّق بين المكونات (Component) وعناصر HTML العادية عن طريق الحرف الأول. <Button> = مكون React. <button> = عنصر HTML.

2. مكون واحد = ملف واحد

ضع كل مكون في ملف منفصل. هيكل المشروع النظيف:

src/ components/ Button/ Button.js Button.css Card/ Card.js Card.css pages/ Home/ Home.js Dashboard/ Dashboard.js

3. تجنب Props Drilling (الحفر العميق)

Props Drilling هو تمرير Props عبر 5-6 مستويات من المكونات. الحل: Context API أو Redux (سنتعلمها لاحقاً).

// ❌ سيء: تمرير Props عبر 4 مستويات <App user={user}> // المستوى 1 <Dashboard user={user}> // المستوى 2 <Sidebar user={user}> // المستوى 3 <UserMenu user={user}> // المستوى 4 — المستهدف! <Avatar user={user} /> </UserMenu> </Sidebar> </Dashboard> </App> // ✅ أفضل: Context API (سنتعلمها في الدرس 5) // أو تمرير مباشر إذا كان المسار قصير

4. استخدم defaultProps للقيم الافتراضية

function Button({ label, variant = 'primary', size = 'medium', disabled = false, onClick }) { return ( <button className={`btn btn-${variant} btn-${size}`} disabled={disabled} onClick={onClick} > {label} </button> ); } // استخدام بسيط — القيم الافتراضية تعمل تلقائياً <Button label="حفظ" onClick={handleSave} /> // استخدام مخصص — تمرير قيم محددة <Button label="حذف" variant="danger" size="small" onClick={handleDelete} />

🚀 تمرين عملي: بناء لوحة تحكم مصغرة

قبل الانتقال للدرس التالي، جرب بناء هذا التطبيق الصغير:

// التحدي: أنشئ تطبيق Dashboard بسيط يحتوي على: // 1. Header مع اسم المستخدم (Props) // 2. Sidebar مع قائمة من 3 عناصر (Composition) // 3. Card يعرض إحصائية (Children + variant) // 4. Footer مع نسخة التطبيق // الهيكل المطلوب: // App // ├── Header (user: {name, avatar}) // ├── main // │ ├── Sidebar (items: ['الرئيسية', 'المنتجات', 'الإعدادات']) // │ └── content // │ ├── Card (title="المستخدمين", variant="stats") → 1,250 // │ ├── Card (title="المبيعات", variant="stats") → ₤ 45,000 // │ └── Card (title="تنبيه", variant="alert") → "5 طلبات جديدة" // └── Footer (version="1.0.0")
📝 تلميح: ابدأ بـ App.js، ثم أنشئ كل مكون في ملف منفصل. استخدم Destructuring في Props. لا تنسَ خاصية key في الحلقات (map). شارك الكود على واتساب 01229068356 وسنراجعه معك!

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

في هذا الدرس تعلمت:

الدرس القادم: سنتعلم Hooks (useState, useEffect) — السر وراء جعل Function Components تفاعلية. سنبني عداد، نافذة منبثقة (Modal)، وقائمة مهام تفاعلية!

🎯 مهمة قبل الدرس القادم: أكمل تمرين Dashboard الصغير. جرب إضافة مكون جديد (مثل NotificationBadge) واستخدمه داخل Header. كلما تمرّنت أكثر، أسرع ستتعلم!