تمرير البيانات إلى المكونات باستخدام الـ Props
| المفهوم الهندسي | طبيعة البيانات في ريأكت | التأثير البرمجي المباشر |
|---|---|---|
| الخصائص Props | كائن ذكي يجمع كل البيانات الممررة من المكون الأب إلى المكون الابن | يسمح بتغذية نفس المكون ببيانات وصور ونصوص مختلفة تماماً في كل مرة |
| القراءة فقط Read-Only | خاصية صارمة تمنع المكون الابن من تعديل أو تغيير الـ props القادمة إليه | تضمن استقرار النظام ومنع العشوائية البرمجية في تتبع تدفق البيانات |
| تفكيك الكائن Destructuring | صياغة جافا سكريبت حديثة لاستخراج المتغيرات من كائن props مباشرة | تجعل الكود نظيفاً للغاية وتغني المطور عن تكرار كلمة props قبل كل متغير |
في الدرس السابق، قمنا ببناء مكون <ProductCard/> وكررناه ثلاث مرات، لكنك لاحظت بالتأكيد مشكلة واضحة: البطاقات الثلاث ظهرت بنفس الاسم ونفس السعر تماماً! في الواقع العملي، نريد أن يعرض المكون اسم وسعر وصورة كل منتج بشكل مختلف بناءً على البيانات القادمة من قاعدة البيانات.
هنا يأتي دور Props (مختصر Properties أو الخصائص)، وهي الوسيلة الرسمية والهندسية التي تتيح للمكونات التحدث مع بعضها وتمرير البيانات من المكون الأب (Parent) إلى المكون الابن (Child).
تخيل الـ Props مثل المعاملات (Arguments) التي تمررها لأي دالة عادية في جافا سكريبت لكي تنتج لك مخرجات مختلفة بناءً على المدخلات.
ℹ️ معلومة
الـ Props في ريأكت هي للقراءة فقط (Read-Only) وتُسمى تقنياً Immutable. هذا يعني أن المكون الابن الذي استقبل البيانات يُحظر عليه تماماً محاولة تعديل قيمة الـ props القادمة إليه يدوياً؛ لأن البيانات في ريأكت تتدفق في اتجاه واحد صارم (من الأعلى للأسفل)، وأي محاولة لتعديلها من الأسفل ستتسبب في انهيار منطق التطبيق.
دعنا نرى التطبيق الفعلي لكيفية إرسال البيانات من الأب وتفكيكها بذكاء داخل المكون الابن باستخدام الصياغة الحديثة لجافا سكريبت (Destructuring):
CourseCard.jsx
| 1 | // بدلاً من كتابة (props) ثم كتابة props.title، نقوم بتفكيك الكائن فوراً داخل الأقواس { } |
| 2 | function CourseCard({ title, price, instructor }) { |
| 3 | return ( |
| 4 | <div style={{ border: '2px solid #673ab7', padding: '20px', borderRadius: '10px', margin: '15px' }}> |
| 5 | {/* استقبال وعرض البيانات الديناميكية القادمة من الأب */} |
| 6 | <h3 style={{ color: '#673ab7' }}>{title}</h3> |
| 7 | <p>المحاضر: {instructor}</p> |
| 8 | <p>السعر: <strong>{price} $</strong></p> |
| 9 | <button style={{ backgroundColor: '#673ab7', color: '#fff', border: 'none', padding: '10px', borderRadius: '5px', cursor: 'pointer' }}> |
| 10 | ابدأ التعلم الآن |
| 11 | </button> |
| 12 | </div> |
| 13 | ); |
| 14 | } |
| 15 | |
| 16 | export default CourseCard; |
App.jsx
| 1 | import CourseCard from './CourseCard'; |
| 2 | |
| 3 | function App() { |
| 4 | return ( |
| 5 | <div className="app-container"> |
| 6 | <h2>لوحة تحكم كورسات نوفيل البرمجية</h2> |
| 7 | |
| 8 | {/* تمرير بيانات فريدة ومختلفة لكل مكون ابن عبر الـ Props */} |
| 9 | <CourseCard |
| 10 | title="كورس ريأكت للمحترفين" |
| 11 | price={49.99} |
| 12 | instructor="أحمد المهندس" |
| 13 | /> |
| 14 | |
| 15 | <CourseCard |
| 16 | title="بناء الواجهات باستخدام Tailwind CSS" |
| 17 | price={29.99} |
| 18 | instructor="سارة علي" |
| 19 | /> |
| 20 | |
| 21 | <CourseCard |
| 22 | title="مقدمة في Node.js و Express" |
| 23 | price={39.99} |
| 24 | instructor="حسن البرمجي" |
| 25 | /> |
| 26 | </div> |
| 27 | ); |
| 28 | } |
| 29 | |
| 30 | export default App; |