لماذا أطر الواجهات؟ أول مكوّن React
من تحديث الصفحة بيدك إلى وصف الواجهة بمكوّنات. ⏱ نحو 30 دقيقة.
- تشرح الفرق بين الأسلوب الأمري والتصريحي، وفائدة المكوّنات.
- تكتب
JSXصحيحًا وتطبّق قواعده الخمس. - تقسّم الواجهة إلى مكوّنات وتربطها بـ
importوexport. - تنشئ مشروع
ReactبـViteوتعرف بنيته.
١مشكلة الواجهات الكبيرة
في مقرر 131 بنيت صفحات تفاعلية بـ JavaScript عادي: تختار عنصرًا بـ querySelector، ثم تغيّره بيدك. هذا ممتاز لصفحة صغيرة، لكن تخيّل متجرًا فيه سلة وقائمة منتجات وعدّاد وإشعارات… كل تغيير في البيانات يتطلب أن تتذكر كل مكان في الصفحة يعرضها:
// JavaScript عادي: نحدّث الصفحة بأيدينا خطوة خطوةconst list = document.querySelector('#list');const count = document.querySelector('#count');let items = []; function addItem(name) { items.push(name); const li = document.createElement('li'); // أنشئ عنصرًا li.textContent = name; list.appendChild(li); // أضفه للقائمة count.textContent = items.length; // ولا تنسَ تحديث العدد!}
هذا الأسلوب اسمه الأمري Imperative: تكتب الخطوات واحدة واحدة. ومع نمو التطبيق تكثر الأخطاء: عدّاد لم يتحدث، أو عنصر تكرر.
أطر الواجهات مثل React تقلب الفكرة: تصف شكل الصفحة لبيانات معيّنة، وحين تتغير البيانات يحدّث الإطار الصفحة بنفسه. هذا الأسلوب التصريحي Declarative:
| JavaScript العادي | React | |
|---|---|---|
| تكتب | خطوات تغيير الصفحة | شكل الصفحة لحالة البيانات |
| عند تغيّر البيانات | تحدّث كل عنصر بيدك | تغيّر البيانات فقط، والإطار يحدّث العرض |
| إعادة الاستخدام | نسخ ولصق للكود | مكوّنات Components تُستخدم مرات كثيرة |
| تنظيم الكود | يتشتت مع كبر الصفحة | كل مكوّن في ملف مستقل بمسؤولية واحدة |
٢React والمكوّنات
React مكتبة JavaScript لبناء الواجهات، طوّرتها Meta، وتُستخدم في مواقع ضخمة. وفكرتها الأساسية: الواجهة شجرة من المكوّنات Components، وكل مكوّن قطعة مستقلة لها شكلها وسلوكها، مثل قطع الليغو:
| المكوّن | مسؤوليته | يتكرر؟ |
|---|---|---|
<Header/> | شعار المتجر وروابط القائمة | مرة في كل صفحة |
<ProductCard/> | صورة المنتج واسمه وسعره وزر الإضافة | مرة لكل منتج |
<Cart/> | المنتجات المختارة والإجمالي | مرة |
<App/> | يجمع المكوّنات كلها | الجذر |
والخطة تذكر أيضًا Vue.js، وهو إطار بالفكرة نفسها: مكوّنات وحالة وتحديث تلقائي. نستخدم React في هذا المقرر لأنه الأوسع انتشارًا في سوق العمل، ولأن مقرر 251 (برمجة الأجهزة الذكية) يبني عليه عبر React Native. وما تتعلمه من مفاهيم ينتقل إلى Vue بسهولة.
٣JSX: HTML داخل JavaScript
المكوّن في React دالة تعيد ما يجب عرضه، مكتوبًا بصياغة JSX التي تشبه HTML. هذا مكوّن كامل، والمعاينة بجانبه تعمل فعلًا:
export default function App() { return ( <div> <h1>مرحبًا بك في أطر الويب</h1> <p>هذا أول مكوّن React تكتبه.</p> </div> );}
وبين القوسين المعقوفين { } تضع أي تعبير JavaScript، فيُحسب ويُعرض:
export default function App() { const name = 'نورة'; const hours = 15; const today = new Date(2026, 9, 14); return ( <div> <h2>أهلًا يا {name}</h2> <p>ساعاتك المسجلة: {hours * 1} ساعة، والمتبقي {20 - hours}.</p> <p>السنة: {today.getFullYear()}</p> </div> );}
٤قواعد JSX الخمس
JSX يشبه HTML لكنه ليس HTML؛ هو JavaScript في النهاية. لذلك له قواعد تختلف قليلًا:
| القاعدة | HTML | JSX |
|---|---|---|
| عنصر جذر واحد | أي عدد من العناصر | عنصر واحد يحيط بالباقي، أو <>…</> |
| الصنف | class="box" | className="box" |
| كل وسم يُغلق | <img src="a.png"> | <img src="a.png" /> |
| السمات بأسلوب camelCase | onclick tabindex | onClick tabIndex |
| التنسيق كائن | style="color:red" | style={{ color: 'red' }} |
export default function App() { return ( <h1>العنوان</h1> <p>الفقرة</p> );}
export default function App() { return ( <> <h1>العنوان</h1> <p>الفقرة</p> </> );}
الدالة تعيد قيمة واحدة فقط، فلا تُرجع عنصرين متجاورين. الغلاف الفارغ <>…</> (Fragment) يجمعهما دون إضافة عنصر للصفحة.
export default function App() { const done = true; return ( <div className="card" style={{ border: '2px solid #149ECA', borderRadius: 12, padding: 12 }}> <hr /> <label htmlFor="n" style={{ display: 'block' }}>الاسم</label> <input id="n" defaultValue="سعود" /> <p style={{ color: done ? 'green' : 'gray' }}>{done ? '✓ مكتمل' : 'قيد العمل'}</p> </div> );}
لاحظ: <hr /> مغلق ذاتيًّا، و htmlFor بدل for، والأرقام في style تعني بكسل. و {{ }} المزدوجة: الخارجية لـ JSX، والداخلية لكائن JavaScript.
٥من مكوّن إلى مكوّنات
المكوّن الكبير يُقسَّم إلى مكوّنات صغيرة. كل مكوّن دالة يبدأ اسمها بحرف كبير، ونستخدمه كأنه وسم: <Header />. وعادةً يكون كل مكوّن في ملف، ونربطها بـ export و import. افتح التبويبات الثلاثة:
import Header from './Header.jsx';import Footer from './Footer.jsx'; export default function App() { return ( <> <Header /> <main> <p>مرحبًا بك في متجر الواحة.</p> </main> <Footer /> </> );}
export default function Header() { return ( <header style={{ background: '#149ECA', color: 'white', padding: 10, borderRadius: 8 }}> <b>☕ متجر الواحة</b> </header> );}
export default function Footer() { return <footer><small>جميع الحقوق محفوظة 2026</small></footer>;}
function header() { return <h2>متجر الواحة</h2>;}export default function App() { return <header />;}
function Header() { return <h2>متجر الواحة</h2>;}export default function App() { return <Header />;}
الاسم بحرف صغير يجعل React يظنه وسم HTML عاديًّا <header> فارغًا، فلا يظهر شيء. أسماء المكوّنات تبدأ دائمًا بحرف كبير.
٦بيئة العمل الحقيقية: Node.js و Vite
المتصفح لا يفهم JSX مباشرة؛ يلزم برنامج يحوّله إلى JavaScript عادي. في هذا المقرر يقوم مختبر React بذلك داخل الصفحة. وعلى جهازك في المعمل تستخدم أداة Vite (تُنطق «ڤيت»):
- ثبّت Node.js (الإصدار الطويل الدعم LTS) من موقعه الرسمي، وتأكد بالأمر
node -v. - أنشئ مشروعًا:
npm create vite@latest my-store -- --template react - ادخل المجلد وثبّت المكتبات:
cd my-storeثمnpm install - شغّل خادم التطوير:
npm run devثم افتحhttp://localhost:5173
| الملف | دوره |
|---|---|
index.html | الصفحة الوحيدة، وفيها <div id="root"> حيث يُرسم التطبيق. |
src/main.jsx | نقطة البداية: يربط React بالعنصر root ويرسم المكوّن App. |
src/App.jsx | المكوّن الجذر الذي ستعدّله. |
package.json | اسم المشروع ومكتباته وأوامره (dev و build). |
import { StrictMode } from 'react';import { createRoot } from 'react-dom/client';import App from './App.jsx'; createRoot(document.getElementById('root')).render( <StrictMode> <App /> </StrictMode>);
في المختبر لا تحتاج main.jsx: نرسم المكوّن المصدَّر افتراضيًّا من App.jsx تلقائيًّا. وحين تحفظ ملفًا في Vite تتحدث الصفحة فورًا، تمامًا كما في المختبر.
٧جرّب بنفسك
توقّع وتحقّق
أي أسلوب تتبعه React؟
Declarative.في JSX يُكتب صنف CSS بالسمة:
class كلمة محجوزة في JavaScript.أي اسم صحيح لمكوّن React؟
الأمر الذي يشغّل خادم التطوير في مشروع Vite:
localhost:5173.الخلاصة
Reactمكتبة واجهات تصريحية: تصف الواجهة للبيانات، فتحدّث العرض وحدها.- المكوّن دالة باسم يبدأ بحرف كبير تعيد
JSX. JSX: عنصر جذر واحد أو <>…>، وclassName، وإغلاق كل وسم، وcamelCase، وstyleكائن، و{}للتعابير.- كل مكوّن في ملف:
export defaultثمimport. Vite: npm create viteثمnpm installثمnpm run dev.
تحدٍّ برمجي: بطاقة تعريف بالمكوّنات
سهلاصنع صفحة تعريف بمتدرب من ثلاثة مكوّنات: رأس، وبطاقة، وتذييل.
- المكوّن
Headerيعرض<h1>ملف المتدرب</h1>. - المكوّن
Cardيعرض الاسم «ريم الشهري» في<h2>، والتخصص في<p className="major">: «تقنية البرمجة وتطوير الويب». - المكوّن
Footerيعرض<footer>فيه «الكلية التقنية». - المكوّن App يجمعها بالترتيب داخل
<>…</>، والاسم يأتي من متغيرname.
👀 اعرض الناتج المطلوب (وجرّبه)
- الكود يعمل بلا أخطاء في Console
- العنوان h1: ملف المتدرب
- الاسم في h2: ريم الشهري
- التخصص في p.major
- التذييل footer: الكلية التقنية
- الترتيب: h1 ثم h2 ثم footer
💡 تلميح 1
💡 تلميح 2
<><Header /><Card /><Footer /></>حاول بنفسك أولًا؛ للمسألة أكثر من حلّ صحيح.
function Header() { return <h1>ملف المتدرب</h1>;} function Card() { const name = 'ريم الشهري'; return ( <div> <h2>{name}</h2> <p className="major">تقنية البرمجة وتطوير الويب</p> </div> );} function Footer() { return <footer>الكلية التقنية</footer>;} export default function App() { return ( <> <Header /> <Card /> <Footer /> </> );}