شرح JSX في React مع أمثلة عملية للمبتدئين والمطورين

دقائق القراءة: 8

ما هو JSX في React؟

يُعد JSX من المفاهيم الأساسية في React، وفهمه بشكل صحيح يساعدك على كتابة واجهات أوضح وأسهل صيانة. ببساطة، JSX هو امتداد نحوي للغة JavaScript يتيح لك كتابة بنية تشبه HTML داخل مكونات React بطريقة مرنة ومقروءة.

في هذا الدليل سنشرح:

  • ما هو JSX ولماذا يُستخدم داخل React.
  • كيف يتحول إلى React.createElement().
  • ما المقصود بتعبيرات JSX وما الذي يمكن كتابته داخلها.
  • أشهر الأخطاء الشائعة وكيفية تجنبها.
  • أفضل الممارسات لكتابة كود أنظف وأكثر احترافية.

شرح مفهوم JSX في React مع أمثلة برمجية عملية

لماذا نستخدم JSX؟

بدون JSX، ستحتاج إلى إنشاء عناصر الواجهة باستخدام استدعاءات مطولة مثل React.createElement(). هذا الأسلوب صحيح تقنياً، لكنه أقل وضوحاً عند بناء واجهات معقدة. أما JSX فيجعل الكود أقرب إلى شكل الواجهة النهائي، وبالتالي يسهل قراءته وتطويره.

مثال بسيط على JSX:

const jsx = <h1>This is JSX</h1>;

قد يبدو هذا السطر شبيهاً بـ HTML، لكنه ليس JavaScript خاماً يفهمه المتصفح مباشرة. لذلك نحتاج إلى أداة مثل Babel لتحويله إلى صيغة قابلة للتنفيذ.

كيف يتعامل المتصفح مع JSX؟

دور Babel في التحويل

المتصفح لا يفهم JSX بشكل مباشر، لأن هذه الصيغة ليست جزءاً أصلياً من JavaScript. هنا يأتي دور Babel، وهو مترجم يحول تعليمات JSX إلى استدعاءات قياسية يفهمها محرك JavaScript.

يمكنك إعداد Babel يدوياً ضمن بيئة مثل Webpack، أو استخدام أدوات جاهزة مثل create-react-app التي تتولى هذه الخطوة تلقائياً.

استخدام JSX داخل مكون

class JSXDemo extends React.Component {
  render() {
    return <h1>This is JSX</h1>;
  }
}

ReactDOM.render(<JSXDemo />, document.getElementById('root'));

في هذا المثال، يعيد المكون JSXDemo عنصراً من نوع JSX، ثم يتم عرضه في الصفحة بواسطة ReactDOM.render().

كيف يتحول JSX إلى React.createElement()؟

عند تنفيذ الشيفرة السابقة، يقوم Babel بتحويلها إلى شيء شبيه بالتالي:

class JSXDemo extends React.Component {
  render() {
    return React.createElement("h1", null, "This is JSX");
  }
}

هذا يوضح أن JSX ليس بديلاً منفصلاً عن React، بل مجرد صيغة مختصرة وأسهل لكتابة استدعاءات React.createElement().

ولهذا السبب، يُطرح كثيراً في المقابلات التقنية سؤال مهم: كيف يتحول JSX داخلياً؟ وفهمك لهذه الآلية يمنحك تصوراً أعمق لكيفية عمل React.

ما وظيفة React.createElement()؟

كل تعليمة JSX تتحول في النهاية إلى استدعاء للدالة React.createElement()، وصيغتها العامة هي:

React.createElement(type, [props], [...children])

شرح الوسائط

  • type: نوع العنصر، مثل h1 أو div، وقد يكون أيضاً مكون React.
  • props: الخصائص أو السمات التي تريد تمريرها للعنصر.
  • children: المحتوى الداخلي، سواء كان نصاً أو عناصر أخرى أو مكونات.

كما يمكن تمثيل العنصر داخلياً في شكل كائن شبيه بالتالي:

{
  type: 'h1',
  props: {
    children: 'This is JSX'
  }
}

معاينة البنية الداخلية لعنصر JSX

class JSXDemo extends React.Component {
  render() {
    const jsx = <h1>This is JSX</h1>;
    console.log(jsx);
    return jsx;
  }
}

ReactDOM.render(<JSXDemo />, document.getElementById('root'));

سجل المتصفح يعرض التمثيل الداخلي لعنصر JSX في React

عند طباعة المتغير jsx في وحدة التحكم، ستلاحظ أن React لا يتعامل معه كنص HTML خام، بل ككائن يصف العنصر وخصائصه.

تمرير الخصائص داخل JSX

إذا أضفت سمة مثل id، فسيتم تمريرها داخل وسيط props في React.createElement().

class JSXDemo extends React.Component {
  render() {
    const jsx = <h1 id="jsx">This is JSX</h1>;
    console.log(jsx);
    return jsx;
  }
}

ReactDOM.render(<JSXDemo />, document.getElementById("root"));

يتم تحويل هذا السطر:

<h1 id="jsx">This is JSX</h1>

إلى:

React.createElement("h1", { id: "jsx" }, "This is JSX");

والتمثيل الداخلي سيكون قريباً من الشكل التالي:

{
  type: 'h1',
  props: {
    id: 'jsx',
    children: 'This is JSX'
  }
}

تحويل JSX مع خاصية id إلى React.createElement في React

إضافة الأحداث داخل JSX

يمكنك تمرير معالجات الأحداث مثل onClick مباشرة داخل العنصر.

class JSXDemo extends React.Component {
  handleOnClick = () => {
    console.log("clicked");
  };

  render() {
    return (
      <button id="btn" onClick={this.handleOnClick}>
        Click Here
      </button>
    );
  }
}

ReactDOM.render(<JSXDemo />, document.getElementById("root"));

والصيغة المكافئة تقريباً ستكون:

React.createElement(
  "button",
  { id: "btn", onClick: function() {} },
  "Click Here"
)

التمثيل الداخلي لعنصر زر في React مع خاصية onClick

هذا يوضح أن جميع الخصائص، بما في ذلك معالجات الأحداث، تُخزن ضمن props.

أداة توضح تحويل JSX إلى React.createElement خطوة بخطوة

كيف تُرجع أكثر من عنصر في JSX؟

من الأخطاء الشائعة محاولة إرجاع أكثر من عنصر متجاور من مكون واحد دون تغليفها بعنصر أب.

import React from "react";
import ReactDOM from "react-dom";

const App = () => {
  return (
    <p>This is first JSX Element!</p>
    <p>This is another JSX Element</p>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

خطأ React عند إرجاع عناصر JSX متجاورة دون عنصر أب

سبب الخطأ أن React يتوقع عنصراً واحداً رئيسياً ليكون نقطة الإرجاع.

الحل الأول: استخدام عنصر أب مثل div

import React from "react";
import ReactDOM from "react-dom";

const App = () => {
  return (
    <div>
      <p>This is first JSX Element!</p>
      <p>This is another JSX Element</p>
    </div>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

الحل الثاني: إرجاع مصفوفة من العناصر

import React from "react";
import ReactDOM from "react-dom";

const App = () => {
  return [
    <p>This is first JSX Element!</p>,
    <p>This is another JSX Element</p>
  ];
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

هذا الأسلوب يعمل، لكنه سيؤدي إلى تحذير يطلب إضافة خاصية key فريدة لكل عنصر.

import React from "react";
import ReactDOM from "react-dom";

const App = () => {
  return [
    <p key="first">This is first JSX Element!</p>,
    <p key="second">This is another JSX Element</p>
  ];
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

الحل الثالث: استخدام React.Fragment

import React from "react";
import ReactDOM from "react-dom";

const App = () => {
  return (
    <React.Fragment>
      <p>This is first JSX Element!</p>
      <p>This is another JSX Element</p>
    </React.Fragment>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

تم تقديم React.Fragment في الإصدار 16.2 لحل مشكلة العناصر المتجاورة دون إضافة عقد إضافية إلى DOM. وهذه ميزة مهمة خصوصاً عندما تؤثر العناصر الزائدة في تنسيق الصفحة، مثل بعض حالات Flexbox.

كيفية كتابة التعليقات داخل JSX

إذا أردت إضافة تعليق داخل بنية JSX، فلا يمكنك استخدام تعليق JavaScript العادي مباشرة. يجب وضعه داخل أقواس معقوفة.

{/* <p>This is some text</p> */}

ويمكنك غالباً استخدام الاختصار Ctrl + / أو Cmd + / لإضافة التعليق أو إزالته بسرعة بحسب المحرر المستخدم.

كيفية إدراج JavaScript داخل JSX

تكمن قوة JSX الحقيقية في إمكانية دمج JavaScript مع عناصر الواجهة بسهولة. يتم ذلك باستخدام الأقواس المعقوفة {}.

const App = () => {
  const number = 10;

  return (
    <div>
      <p>Number: {number}</p>
    </div>
  );
};

ما تضعه داخل الأقواس المعقوفة يجب أن يكون تعبيراً ينتج قيمة يمكن عرضها أو استخدامها.

ما الذي يمكن كتابته داخل تعبيرات JSX؟

  • نصوص مثل "hello".
  • أرقام مثل 10.
  • مصفوفات مثل [1, 2, 3].
  • خصائص كائن مثل user.name.
  • استدعاءات دوال مثل getTitle().
  • الدالة map() لإرجاع عناصر متعددة.
  • بنية JSX أخرى ناتجة من تعبير شرطي.

ما الذي لا يمكن كتابته مباشرة داخل تعبيرات JSX؟

  • جمل التكرار مثل for وwhile.
  • تعريف المتغيرات مثل const وlet.
  • تعريف الدوال.
  • جمل if التقليدية.
  • الكائنات الخام بالشكل المباشر.

السبب أن JSX يقبل تعبيرات تُقيَّم إلى قيمة، بينما التعليمات مثل if أو for هي أوامر تحكم وليست قيماً قابلة للعرض مباشرة.

لماذا تُعرض المصفوفات ولا تُعرض الكائنات؟

يمكن عرض المصفوفة داخل JSX لأن React يستطيع التعامل مع عناصرها وطباعتها بالتتابع. أما الكائن الخام، فلا توجد طريقة افتراضية واضحة لعرضه: هل يظهر كـ JSON أم كأزواج key/value؟ لذلك ينتج عن عرضه خطأ.

لكن يمكنك الوصول إلى خاصية من الكائن وعرضها بشكل طبيعي، مثل user.name.

ومن المهم أيضاً معرفة أن القيم undefined وnull وboolean لا تظهر على الواجهة عند استخدامها مباشرة داخل JSX.

إذا أردت عرض قيمة منطقية مثل true أو false، يمكنك تحويلها إلى نص باستخدام template literal:

const App = () => {
  const isAdmin = true;

  return (
    <div>
      <p>isAdmin is {`${isAdmin}`}</p>
    </div>
  );
};

استخدام الشروط داخل JSX

لا يمكنك كتابة جملة if مباشرة داخل أقواس JSX، لكن يمكنك استخدام عوامل شرطية مناسبة مثل العامل الثلاثي ternary أو العامل المنطقي &&.

<p>{a > b ? "Greater" : "Smaller"}</p>
<p>{shouldShow && "Shown"}</p>

هذه الطريقة شائعة جداً في React، وتساعدك على إبقاء منطق العرض مختصراً وواضحاً.

التعبيرات الشرطية المتداخلة

const App = () => {
  const number = 10;

  return (
    <div>
      {number > 0 ? (
        <p>Number {number} is positive</p>
      ) : (
        <p>Number {number} is negative</p>
      )}
    </div>
  );
};

يسمح لك هذا الأسلوب بعرض واجهات مختلفة حسب الحالة، مع الحفاظ على منطق العرض داخل المكون نفسه.

كيفية إضافة class وid في JSX

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

import React from "react";
import ReactDOM from "react-dom";

const App = () => {
  const id = "some-id";

  return (
    <div>
      <h1 id={id}>This is a heading</h1>
      <h2 className="active">This is another heading</h2>
    </div>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

لماذا نستخدم className بدلاً من class؟

في React يجب استخدام className بدلاً من class. السبب أن class كلمة محجوزة في JavaScript، واستخدامها بنفس معنى HTML قد يسبب تعارضاً أو تحذيرات.

تحذير React عند استخدام class بدلاً من className داخل JSX

عند فحص التمثيل الداخلي، ستجد أن الخاصية تُخزّن ضمن props، لكن الوصول إلى props.class ليس خياراً مناسباً بسبب تعارض الكلمة مع قواعد اللغة.

عرض خاصية class داخل props في التمثيل الداخلي لعناصر React

ولهذا يُعد سؤال الفرق بين class وclassName من الأسئلة المتكررة في مقابلات React.

تنسيق أسماء السمات في React

معظم أسماء السمات في React تُكتب بصيغة camelCase، وليس بنفس كتابة HTML التقليدية دائماً. لذلك من المهم الانتباه إلى هذه النقطة عند التعامل مع السمات والأحداث.

أشهر الأخطاء الشائعة في JSX

  • إرجاع أكثر من عنصر متجاور دون عنصر أب أو React.Fragment.
  • استخدام class بدلاً من className.
  • كتابة جملة if أو حلقة for مباشرة داخل أقواس JSX.
  • نسيان إضافة key فريد عند عرض قائمة عناصر.
  • محاولة عرض كائن خام داخل الواجهة.

نصائح عملية لكتابة JSX أفضل

  • استخدم JSX لزيادة وضوح الواجهة، لا لتعقيدها.
  • قسّم الواجهة إلى مكونات صغيرة عند تضخم الشيفرة.
  • أخرج المنطق المعقد خارج جزء الإرجاع return كلما أمكن.
  • استخدم React.Fragment عندما لا تحتاج إلى عنصر DOM إضافي.
  • احرص على أن تكون التعبيرات داخل JSX بسيطة وسهلة القراءة.

أهم النقاط التي يجب تذكرها

  • كل عنصر JSX يتحول في النهاية إلى React.createElement().
  • تعبيرات JSX تقبل القيم الناتجة من تعبيرات، لا الأوامر البرمجية الكاملة.
  • استخدم className بدلاً من class.
  • أسماء السمات في React تُكتب غالباً بصيغة camelCase.
  • القيم undefined وnull وboolean لا تظهر مباشرة في واجهة المستخدم.

الخلاصة التقنية

يمنحك فهم JSX قدرة أكبر على كتابة مكونات React بطريقة أكثر وضوحاً ومرونة. ورغم أن JSX يبدو شبيهاً بـ HTML، فإنه في الحقيقة طبقة تعبيرية تُترجم إلى استدعاءات برمجية دقيقة. كلما فهمت آلية التحويل إلى React.createElement()، أصبحت قراراتك في بناء المكونات، وتمرير props، ومعالجة الشروط والقوائم أكثر احترافية. من الناحية العملية، يمكن اعتبار JSX أفضل نقطة انطلاق لفهم فلسفة React في بناء الواجهات declaratively وبأسلوب قابل للتوسع.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *