شرح JSX بالتفصيل

من موسوعة حسوب

توفِّر JSX علينا عناء إنشاء العناصر باستخدام الدالة React.createElement(component, props, ...children)‎. انظر إلى الشيفرة التالية في JSX:

<MyButton color="blue" shadowSize={2}>
  انقر هنا
</MyButton>

تُترجَم الشيفرة السّابقة إلى:

React.createElement(
  MyButton,
  {color: 'blue', shadowSize: 2},
  'انقر هنا'
)

بإمكانك أيضًا استخدام الشكل ذاتي الإغلاق للعنصر إن كان لا يحتوي على أيّة عناصر أبناء:

<div className="sidebar" />

تُترجَم الشيفرة السّابقة إلى:

React.createElement(
  'div',
  {className: 'sidebar'},
  null
)

إن أردتَ اختبار كيفيّة تحويل بعض شيفرات JSX إلى JavaScript فبإمكانك تجريب مُترجِم Babel على الإنترنت.

تحديد نوع عنصر React

يُحدِّد أول عنصر في شيفرة JSX نوع عنصر React. تُشير الأنواع المكتوبة بأحرف كبيرة إلى أنّ العنصر المذكور هو مُكوِّن React. تُترجَم هذه العناصر إلى مرجع مباشر إلى المتغيّر الذي يحمل اسمها، لذا إن استخدمت التعبير ‎<Foo />‎ في JSX يجب أن يكون المتغيّر Foo في نفس المجال.

يجب على React أن تكون في نفس المجال

لمّا كانت JSX تُترجَم إلى نداءات للتابع React.createElement، فيجب على مكتبة React أن تكون في نفس المجال الذي تكون فيه شيفرة JSX.

على سبيل المثال الاستيراد التالي ضروري في هذه الشّيفرة على الرغم من أنّ React و CustomButton لا يُشار إليهما بشكل مباشر من JavaScript:

import React from 'react';
import CustomButton from './CustomButton';

function WarningButton() {
  
  return <CustomButton color="red" />;
  // تُكافئ: return React.createElement(CustomButton, {color: 'red'}, null);
}

إن لم تستخدم مُحزِّم JavaScript وطلبتَ React من داخل عنصر <script>، فهي موجودة مُسبقًا في نفس المدى لأنّها عامّة (global).

استخدام النقطة لأنواع JSX

بإمكانك الإشارة أيضًا إلى مُكوِّن React باستخدام النقطة من داخل JSX. وهو أمرٌ جيّد إن كانت لديك وحدة (module) وحيدة والتي تُصدِّر عدّة مُكوِّنات React. على سبيل المثال إن كان MyComponents.DatePicker مُكوِّنًا، فيُمكِنك استخدامه بشكلٍ مباشر من JSX كما يلي:

import React from 'react';

const MyComponents = {
  DatePicker: function DatePicker(props) {
    return <div>تخيّل وجود {props.color} انتقاء للتاريخ هنا.</div>;
  }
}

function BlueDatePicker() {
  return <MyComponents.DatePicker color="blue" />;
}

يجب كتابة المكونات المعرفة من قبل المستخدم بأحرف كبيرة

عندما يبدأ نوع العنصر بحرف صغير، فهو يُشير إلى مُكوِّنات داخليّة مثل <div> أو <span> وينتج عنه السلسلة النصيّة 'div' أو 'span' والتي تُمرَّر إلى التّابع React.createElement. أمّا الأنواع التي تبدأ بأحرف كبيرة مثل ‎<Foo />‎ فتُترجَم إلى React.createElement(Foo)‎ وتُوافِق مُكوِّنات مُعرَّفة أو مُستوردة في ملّف JavaScript لديك.

نوصي بتسمية المُكوِّنات بأحرف كبيرة، وإن كان لديك مُكوِّن يبدأ بحرف صغير فعيّنه إلى مُتغيّر يبدأ بحرف كبير قبل استخدامه في JSX.

على سبيل المثال لن تعمل الشيفرة التالية كما هو مُتوقَّع:

import React from 'react';

// :خطأ! هذا مُكوِّن ويجب أن يبدأ بحرف كبير
function hello(props) {
  // صحيح! هنا استخدام العنصر div صحيح كونه عنصر في HTML
  return <div>أهلًا {props.toWhat}</div>;
}

function HelloWorld() {
  // خطأ! تعتقد React أنّ العنصر hello هو عنصر في HTML لأنّه لا يبدأ بحرف كبير
  return <hello toWhat="بالعالم" />;
}

لإصلاح ذلك سنُعيد تسمية hello إلى Hello وسنستخدم ‎<Hello />‎ للإشارة إليه:

import React from 'react';

// صحيح! هذا مُكوِّن ويجب أن يبدأ بحرف كبير
function Hello(props) {
  // صحيح! هنا استخدام العنصر div صحيح كونه عنصر في HTML
  return <div>أهلًا {props.toWhat}</div>;
}

function HelloWorld() {
  // صحيح! تعلم React أنّ Hello هو مُكوِّن لأنّه يبدأ بحرف كبير
  return <Hello toWhat="بالعالم" />;
}

اختيار النوع في زمن التنفيذ

لا يُمكنِك استخدام تعبير عام كنوع لعنصر React، فإن لم ترغب باستخدام تعبير عام للإشارة لنوع العنصر، فعيّنه فقط إلى متغيّر يبدأ بحرف كبير أولًا. يحدث هذا عادةً عندما تريد تصيير مُكوِّن آخر بناءً على خاصيّة prop:

import React from 'react';
import { PhotoStory, VideoStory } from './stories';

const components = {
  photo: PhotoStory,
  video: VideoStory
};

function Story(props) {
  // خطأ! لا يمكن أن يكون نوع JSX عبارة عن تعبير
  return <components[props.storyType] story={props.story} />;
}

لإصلاح ذلك سنُعيِّن النوع إلى متغيّر يبدأ بحرف كبير أولًا:

import React from 'react';
import { PhotoStory, VideoStory } from './stories';

const components = {
  photo: PhotoStory,
  video: VideoStory
};

function Story(props) {
  // صحيح! يُمكِن لنوع JSX أن يكون متغيّرًا يبدأ بحرف كبير
  const SpecificStory = components[props.storyType];
  return <SpecificStory story={props.story} />;
}

الخاصيّات props في JSX

هنالك عدّة طرق لتحديد الخاصيّات في JSX.

تعابير JavaScript كخاصيّات

بإمكانك تمرير أي تعبير JavaScript كخاصيّة prop عن طريق إحاطته بالقوسين {}‎. على سبيل المثال:

<MyComponent foo={1 + 2 + 3 + 4} />

بالنسبة للمُكوِّن MyComponent تكون قيمة props.foo هي 10 بسبب تقييم التعبير ‎1 + 2 + 3 + 4‎. لا تُعدُّ جمل if الشرطيّة و حلقات for تعابيرًا في JavaScript، لذلك لا يُمكِن استخدامها في JSX بشكلٍ مباشر، وبدلًا من ذلك بإمكاننا وضعها في الشيفرة المُحيطة. على سبيل المثال:

function NumberDescriber(props) {
  let description;
  if (props.number % 2 == 0) {
    description = <strong>زوجي</strong>;
  } else {
    description = <i>فردي</i>;
  }
  return <div>{props.number} هو عدد {description}</div>;
}

يُمكِنك تعلّم المزيد حول التصيير الشرطي واستخدام الحلقات في أقسامها الخاصّة.

استخدام السلاسل النصيّة الحرفيّة

بإمكانك تمرير سلسلة نصيّة حرفيّة كخاصيّة، فالتعبيران التاليان في JSX مُتكافئان:

<MyComponent message="hello world" />

<MyComponent message={'hello world'} />

عندما تُمرِّر سلسلة نصيّة حرفيّة، ستُهرَّب قيمتها (HTML-unescaped) بشكلٍ افتراضي. لذلك التعبيران التاليان مُتكافئان أيضًا:

<MyComponent message="&lt;3" />

<MyComponent message={'<3'} />

لا علاقة لهذا السّلوك بموضوعنا، ولكن ذكرناه هنا من أجل الفائدة.

القيمة الافتراضيّة للخاصيّات props هي true

إن لم تُمرِّر أي قيمة للخاصيّة فقيمتها الافتراضيّة هي true. التعبيران التاليان مُتكافئان:

<MyTextBox autocomplete />

<MyTextBox autocomplete={true} />

لا نُوصي إجمالًا بفعل ذلك بسبب الارتباك الذي يُسبّبه التشابه مع الصيغة المختصرة للكائنات في ES6، حيث تكون ‎{foo}‎ اختصارًا إلى ‎{foo: foo}‎ بدلًا من ‎{foo: true}‎ كما قد تظن. هذا السّلوك موجود هنا فقط للتوافق مع سلوك HTML.

خاصيّات النشر

إن كانت لديك خاصيّات props على شكل كائنات، وأردتَ تمريرها في JSX، فبإمكانك استخدام مُعامِل النشر … لتمرير كائن الخاصيّات بشكلٍ كامل. المُكوِّنان التاليان مُتكافئان: