طَبِّقْهاتعلّم المبدأ، وطبّقه بيدكمقرر 242 · أطر الويب
الدرس 1 · الوحدة 1: إتقان الهندسة المعتمدة على المكوّنات

لماذا أطر الواجهات؟ أول مكوّن 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 في النهاية. لذلك له قواعد تختلف قليلًا:

القاعدةHTMLJSX
عنصر جذر واحدأي عدد من العناصرعنصر واحد يحيط بالباقي، أو <>…</>
الصنفclass="box"className="box"
كل وسم يُغلق<img src="a.png"><img src="a.png" />
السمات بأسلوب camelCaseonclick tabindexonClick 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 />    </>  );}
✗ خطأ
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 (تُنطق «ڤيت»):

  1. ثبّت Node.js (الإصدار الطويل الدعم LTS) من موقعه الرسمي، وتأكد بالأمر node -v.
  2. أنشئ مشروعًا: npm create vite@latest my-store -- --template react
  3. ادخل المجلد وثبّت المكتبات: cd my-store ثم npm install
  4. شغّل خادم التطوير: 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عدّل الكود؛ تتحدث المعاينة وحدها. جرّب أن تحذف الغلاف div وتلاحظ رسالة الخطأ.

توقّع وتحقّق

أي أسلوب تتبعه React؟

Declarative.

في JSX يُكتب صنف CSS بالسمة:

لأن class كلمة محجوزة في JavaScript.

أي اسم صحيح لمكوّن React؟

يبدأ بحرف كبير.

الأمر الذي يشغّل خادم التطوير في مشروع Vite:

ثم افتح localhost:5173.

الخلاصة

تحدٍّ برمجي: بطاقة تعريف بالمكوّنات

سهل

اصنع صفحة تعريف بمتدرب من ثلاثة مكوّنات: رأس، وبطاقة، وتذييل.

المطلوب:
  • المكوّن Header يعرض <h1>ملف المتدرب</h1>.
  • المكوّن Card يعرض الاسم «ريم الشهري» في <h2>، والتخصص في <p className="major">: «تقنية البرمجة وتطوير الويب».
  • المكوّن Footer يعرض <footer> فيه «الكلية التقنية».
  • المكوّن App يجمعها بالترتيب داخل <>…</>، والاسم يأتي من متغير name.
👀 اعرض الناتج المطلوب (وجرّبه)
✓ التحقق الآلي من حلّك:
  • الكود يعمل بلا أخطاء في Console
  • العنوان h1: ملف المتدرب
  • الاسم في h2: ريم الشهري
  • التخصص في p.major
  • التذييل footer: الكلية التقنية
  • الترتيب: h1 ثم h2 ثم footer

💡 تلميح 1
كل مكوّن دالة تبدأ بحرف كبير وتعيد JSX.
💡 تلميح 2
في App: <><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 />    </>  );}
انتقل إلى تقييم الدرساختيار من متعدد، وصح وخطأ، وأكمل الفراغ، وتتبّع الناتج.ابدأ التقييم ←

📝 معلم؟ أرسل ملاحظة للمؤلف عن هذا الدرس