EduFlow
أساسيات React
⁦0%⁩

الوحدة 1 · البداية

قواعد JSX الأساسية

17 دقراءة 4 دبيئة تجريب الكود

الدرس في لمحة

اقرأ JSX واكتبه من دون صراع مع المترجم، بمعرفة ما يتحوّل إليه، وكيف تعمل الأقواس المعقوصة، وما قواعد الخصائص والعرض التي تختلف عن HTML.

  1. 1JSX مجرّد استدعاءات دوال
  2. 2الأقواس المعقوصة تحمل تعبيرات
  3. 3الخصائص أسماء JavaScript
  4. 4أغلق كل وسم
  5. 5ما الذي يمكن عرضه

لا فيديو هنا، بل الشيء الحقيقي: درس مكتوب وأمثلة قابلة للتشغيل واختبار وتدريب.

يبدو JSX مثل HTML، فيكون أول ما يخطر لك أن تكتب HTML. وهذا ينجح في أغلب الأحيان. ثم تكتب class="card" فيظهر تحذير في الـ console، أو تضع if داخل أقواس معقوصة فتحصل على خطأ ترجمة يشير إلى السطر الخطأ. كل واحدة من هذه المفاجآت تصبح منطقية حين ترى حقيقة JSX.

JSX مجرّد استدعاءات دوال

يترجم Vite كل وسم JSX إلى استدعاء دالة. هذا الـ component:

JSX
function MovieCard() {
  return <h2 className="title">Arrival</h2>;
}

يتحوّل إلى ما يشبه هذا:

JavaScript
import { jsx } from 'react/jsx-runtime';

function MovieCard() {
  return jsx('h2', { className: 'title', children: 'Arrival' });
}

يُرجع الاستدعاء كائن JavaScript عاديًا اسمه React element: وصف خفيف لما يجب أن يظهر على الشاشة، له type وبعض الـ props. يمكنك تمثيل الفكرة بدالة صغيرة من عندك:

JavaScript
function h(type, props, ...children) {
  return { type, props: { ...props, children } };
}

const card = h('article', { className: 'card' },
  h('h2', null, 'Arrival'),
  h('p', null, 2016),
);

console.log(card.type);                         // article
console.log(card.props.className);              // card
console.log(card.props.children[0].props.children); // ["Arrival"]

عناصر React الحقيقية تحمل معلومات أكثر قليلًا، لكن الشكل هو نفسه. تمرّ React على شجرة الكائنات هذه وتُنشئ الـ DOM أو تحدّثه ليطابقها.

لاحظ أن الكود المترجَم يستورد jsx نيابةً عنك. لهذا لا تبدأ ملفات React الحديثة بالسطر import React from 'react'. الدروس القديمة تتضمّن هذا السطر لأن المترجم السابق كان يحوّل JSX إلى استدعاءات React.createElement(…)، التي تحتاج إلى وجود React في النطاق. ومنذ الـ JSX runtime التلقائي في React 17 لم يعد ضروريًا، فاحذفه.

يُترجَم مصدر JSX إلى استدعاء للدالة jsx، يُرجع كائنًا عاديًا له type وprops؛ ثم ترسم React هذا الكائن في عقدة DOM حقيقية. ما تكتبه <h2>Arrival</h2> ما ينتجه المترجم { type: 'h2', props: {…} } ما تثبّته React عقدة DOM <h2> عناصر React أوصاف، لا عُقد DOM
يتحوّل JSX إلى كائن عنصر، ثم إلى DOM

حين تعرف أن JSX استدعاءات دوال، تتوقّف القواعد التالية عن الظهور كأنها اعتباطية.

الأقواس المعقوصة تحمل تعبيرات

داخل JSX، تعيدك { } إلى JavaScript. وكل ما تضعه بداخلها يصبح وسيطًا لاستدعاء دالة، لذا يجب أن يكون تعبيرًا (expression): شيئًا ينتج قيمة.

JSX
function MovieCard() {
  const movie = { title: 'Arrival', year: 2016, rating: 8 };
  const age = 2026 - movie.year;

  return (
    <article>
      <h2>{movie.title.toUpperCase()}</h2>
      <p>{movie.year} · {age} years old</p>
      <p>{movie.rating >= 8 ? 'Must watch' : 'Maybe'}</p>
    </article>
  );
}

المتغيّرات والوصول إلى الخصائص واستدعاء الدوال والعمليات الحسابية والمعامل الثلاثي a ? b : c كلها تعبيرات. أمّا if وfor وconst فجُمل (statements)، فلا يمكن وضعها داخل الأقواس، تمامًا كما لا يمكنك تمرير if (x) {} وسيطًا لدالة. وحين يكبر المنطق، احسب متغيّرًا فوق return واستخدمه.

هذه هي البطاقة نفسها مع وصف يحتاج إلى تفرّع حقيقي. تعيش جملة if في JavaScript عادية فوق return، ولا يستقبل JSX إلا القيمة النهائية:

JSX
function MovieCard({ movie }) {
  let label;
  if (movie.rating >= 9) {
    label = 'Masterpiece';
  } else if (movie.rating >= 7) {
    label = 'Must watch';
  } else {
    label = 'Maybe';
  }

  return <p>{movie.title}: {label}</p>;
}

هذا النمط يتوسّع جيدًا. يبقى الـ JSX صورة مقروءة للمخرجات، وتبقى القرارات في كود عادي يمكنك قراءته واختباره وتتبّع أخطائه كأي دالة أخرى. (الـ { movie } في قائمة المعاملات prop؛ ستتعلّم الـ props كما يجب في القسم التالي.)

الخصائص تأخذ أقواسًا معقوصة أيضًا: <img src={movie.poster} alt={movie.title} />. لا تضع الأقواس داخل علامات اقتباس؛ فـ src="{poster}" هو النص الحرفي {poster}.

الخصائص أسماء JavaScript

لأن الـ props تصبح مفاتيح في كائن JavaScript، فهي تتبع قواعد التسمية في JavaScript:

  • class تصبح className، وfor تصبح htmlFor (كلتاهما كلمة محجوزة في JS).
  • الخصائص المكوّنة من عدّة كلمات تُكتب بصيغة camelCase: onClick وtabIndex وautoComplete وmaxLength.
  • خصائص aria-* وdata-* تحتفظ بالشَّرطات: aria-label="Remove" وdata-id="42".
  • تأخذ style كائنًا، بخصائص CSS بصيغة camelCase: style={{ marginTop: 8 }}. والرقم المجرّد يعني بكسلات في أغلب الخصائص. والأقواس المزدوجة هي كائن حرفي داخل تعبير JSX.

أغلق كل وسم

JSX أكثر صرامة من HTML. كل عنصر يجب أن يُغلق: <img /> و<input /> و<br />. والـ component يُرجع جذرًا واحدًا، ملفوفًا بـ fragment <>…</> إن احتجت إلى عناصر متجاورة. والتعليقات توضع داخل أقواس معقوصة: {/* like this */}.

ما الذي يمكن عرضه

ما تضعه بين الأقواس ما يظهر
نص أو رقم النص نفسه (بما في ذلك 0)
عنصر React ذلك العنصر
مصفوفة من العناصر كل عنصر بالترتيب
null وundefined وtrue وfalse لا شيء
كائن عادي خطأ: «Objects are not valid as a React child»

صفّ «لا شيء» هو ما يجعل العرض الشرطي ممكنًا، والـ 0 في الصف الأول فخّ شهير ستقابله في درس العرض الشرطي.

صار بإمكانك قراءة أي JSX وتوقّع ما يفعله. في القسم التالي تتوقّف عن كتابة “Arrival” يدويًا، وتتعلّم التفكير بالـ components، فتقسّم شاشة كاملة إلى قطع تستقبل بياناتها عبر الـ props.

أهم النقاط

  • يتحوّل JSX إلى استدعاءات دوال تُنشئ كائنات JavaScript عادية تصف الواجهة، ثم تحوّل React هذه الكائنات إلى DOM.
  • تضمّ الأقواس المعقوصة أي تعبير JavaScript (قيمة)، لكنها لا تقبل أبدًا جملة مثل if أو for.
  • الخصائص أسماء JavaScript بصيغة camelCase، لذا تكتب className وhtmlFor وonClick، وتمرّر إلى style كائنًا.
  • النصوص والأرقام تُعرض كنص، بينما null وundefined وtrue وfalse لا تعرض شيئًا، والكائنات العادية ترمي خطأ.

قراءات إضافية

تحقّق من فهمك

4 أسئلة

السؤال 1 من 4

إلى ماذا يتحوّل <h2 className="title">{movie.title}</h2> بعد أن يترجمه Vite؟

السؤال 2 من 4

أيّ سطر هو JSX صحيح؟

السؤال 3 من 4

قيمة movie هي { title: 'Arrival', year: 2016 }. ماذا يحدث مع <p>{movie}</p>؟

السؤال 4 من 4

يحتوي وصف أحد الأفلام القادم من الـ API على <b>Must watch</b>. تعرضه بالشكل <p>{movie.description}</p>. ماذا يظهر؟

تدريب

بيئة تجريب الكود

ترجم JSX بيدك

JSX مجرّد استدعاءات دوال. يعطيك كود البداية الدالة h(type, props, ...children)، وهي نسخة مبسّطة مما ينتجه المترجم. أكمل buildCard(movie) لتُرجع بالضبط ما سينشئه هذا الـ JSX:

JSX
<article className="card">
  <h2>{movie.title}</h2>
  <p>{movie.year}</p>
</article>

استخدم الوسيط movie، لا قيمًا مكتوبة يدويًا.

// A tiny stand-in for what JSX compiles to.
function h(type, props, ...children) {
  return { type, props: { ...props, children } };
}

// Write the h() calls this JSX compiles to:
//
// <article className="card">
//   <h2>{movie.title}</h2>
//   <p>{movie.year}</p>
// </article>
function buildCard(movie) {
  return h('article', null);
}
جارٍ تحميل المحرّر…

Ctrl/⌘ + Enter للتشغيل · يعمل في بيئة معزولة داخل متصفّحك. لا شيء يغادر جهازك.

الـ console

(لا مخرجات)

الفحوص

  • الجذر “article” وقيمة className فيه “card”
  • له ابنان: “h2” ثم “p”
  • يحتوي الـ h2 على عنوان الفيلم
  • يعمل مع أي فيلم، لا مع Arrival فقط