قد تحتاج مكوناتك أحيانًا إلى عرض أشياء مختلفة اعتمادًا على حالات مختلفة. في React، يمكنك عرض JSX شَرطيّا باستعمال صيغة JavaScript مثل تعليمات if، && و عمليات ? :.

You will learn

  • كيفية إرجاع JSX مختلف وفقًا لشرط معين؟
  • كيفية تضمين أو استبعاد جزء من JSX شَرطيّا
  • اختصارات بناء الجمل الشرطية الشائعة التي ستصادفها في أكواد React.

إرجاع JSX شَرطيّا

لنفترض أن لديك مكون PackingList يقوم بعرض عدة مكونات Item، والتي يمكن تمييزها على أنها محزومة أو لا:

function Item({ name, isPacked }) {
  return <li className="item">{name}</li>;
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

لاحظ أن بعض مكونات Item لديها خاصية isPacked معينة إلى true بدلا من false. ترغب في إضافة علامة التحقق (✔) إلى العناصر المحزومة في حالة isPacked={true}.

يمكنك كتابة ذلك باستخدام عبارة if/else على النحو التالي:

if (isPacked) {
return <li className="item">{name}</li>;
}
return <li className="item">{name}</li>;

إذا كانت خاصية isPacked صحيحة (true)، فإن هذا الكود يُرجع شجرة JSX مختلفة. مع هذا التغيير، تحصل بعض العناصر على علامة التحقق في النهاية:

function Item({ name, isPacked }) {
  if (isPacked) {
    return <li className="item">{name}</li>;
  }
  return <li className="item">{name}</li>;
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

جرب تعديل ما يتم إرجاعه في كلتا الحالتين، وشاهد كيف تتغير النتيجة!

لاحظ أنك تقوم بإنشاء منطق تفريعي باستخدام تعليمات جافاسكريبت if و return. في React، يتم التحكم في التدفق (مثل الشروط) باستخدام JavaScript.

عدم إرجاع شيء شَرطيّا باستعمال null

في بعض الحالات، قد ترغب في عدم عرض أي شيء على الإطلاق. على سبيل المثال، قد ترغب في عدم عرض العناصر المحزومة. يجب على المكون أن يرجع قيمة. في هذه الحالة، يمكنك إرجاع القيمة null:

if (isPacked) {
return null;
}
return <li className="item">{name}</li>;

إذا كانت قيمة isPacked صحيحة (true)، فلن يُرجع المكون شيئًا، أي null. وإلا، سيقوم بإرجاع JSX للعرض.

function Item({ name, isPacked }) {
  if (isPacked) {
    return null;
  }
  return <li className="item">{name}</li>;
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

من الناحية العملية، إعادة قيمة null من مكون ليست شائعة لأنها قد تفاجئ المطور الذي يحاول عرضها. غالبًا، ستقوم بتضمين المكون شَرطيّا أو استبعاده في JSX الخاص بالمكون الأب. إليك كيفية القيام بذلك!

تضمين JSX شَرطيّا

في المثال السابق، تحكمت في شجرة JSX (إن وجدت!) التي سيُرجعها المكون. ربما لاحظت بالفعل بعض التكرار في ناتج العرض:

<li className="item">{name}</li>

مشابه جدًا لـ

<li className="item">{name}</li>

كلا الفرعين المشروطين يعيدان <li className="item">...</li>:

if (isPacked) {
return <li className="item">{name}</li>;
}
return <li className="item">{name}</li>;

بينما هذا التكرار ليس ضارًا، إلا أنه قد يجعل الكود أكثر صعوبة في الصيانة. ماذا لو أردت تغيير قيمة className؟ ستضطر للقيام بذلك في مكانين في الكود! في مثل هذه الحالة، يمكنك تضمين القليل من JSX شَرطيّا لجعل الكود الخاص بك خاليًا من التكرار DRY.

العامل (الثلاثي) الشرطي (? :)

يحتوي JavaScript على صيغة مختصرة لكتابة تعبير شرطي — العامل الشرطي أو ”العامل الثلاثي“ (ternary operator).

بدلا من هذا:

if (isPacked) {
return <li className="item">{name}</li>;
}
return <li className="item">{name}</li>;

يمكنك كتابة هذا:

return (
<li className="item">
{isPacked ? name + ' ✔' : name}
</li>
);

يمكنك قرائتها على النحو التالي ”إذا كان isPacked صحيحا، إذا قم بعرض name + ' ✔'، وإلا (:) قم بعرض name“.

Deep Dive

هل هذان المثالان متساويان تمامًا؟

إذا كنت قادمًا من خلفية البرمجة كائنية التوجه OOP، فقد تفترض أن المثالين أعلاه يختلفان اختلافًا طفيفًا لأن أحدهما قد ينشئ “حالتين” (instance) مختلفين من <li>. لكن عناصر JSX ليست “حالات” لأنها لا تحتوي على أي حالة داخلية وليست عناصر DOM حقيقية. إنما هي أوصاف خفيفة، مثل المخططات. إذن هذان المثالان، في الواقع، متساويان تمامًا. يتناول الحفاظ على الحالة وإعادة تعيينها كيفية عمل هذا بالتفصيل.

الآن لنفترض أنك ترغب في وضع النص الخاص بالعناصر المكتملة في عنصر HTML إضافي كـ<del> لشطبه. يمكنك إضافة المزيد من الأسطر الجديدة والأقواس حتى يكون من الأسهل تضمين JSX إضافي في كل حالة:

function Item({ name, isPacked }) {
  return (
    <li className="item">
      {isPacked ? (
        <del>
          {name + ' ✔'}
        </del>
      ) : (
        name
      )}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

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

العامل المنطقي AND (&&)

الاختصار الشائع الآخر الذي ستصادفه هو العامل المنطقي AND (&&) في JavaScript. داخل مكونات React، غالبًا ما تظهر عندما تريد عرض بعض JSX فقط عندما يكون الشرط صحيحًا، وعدم عرض أي شيء في حالة الشرط غير الصحيح. باستخدام العامل &&، يمكنك عرض علامة التحقق شَرطيّا فقط إذا كانت قيمة isPacked صحيحة true:

return (
<li className="item">
{name} {isPacked && '✔'}
</li>
);

يمكنك قرائتها على النحو التالي “إذا كانت isPacked صحيحة، إذن (&&) يعرض علامة التحقق، وإلا لا تعرض أي شيء”

وإليك كيف يتم تطبيقها عمليًا:

function Item({ name, isPacked }) {
  return (
    <li className="item">
      {name} {isPacked && '✔'}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

عبارة && في JavaScript تقوم بارجاع الجانب الأيمن من العبارة (في حالتنا، علامة التحقق) إذا كان الجانب الأيسر (شرطنا) صحيحًا true. ولكن إذا كان الشرط غير صحيح false، فإن التعبير بأكمله يصبح غير صحيح false. يعتبر React القيمة غير الصحيحة false “فجوة” في شجرة JSX، تمامًا مثل القيمتين null أو undefined، ولا يتم عرض أي شيء مكانها.

Pitfall

لا تضع أرقامًا على الجانب الأيسر من &&.

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

على سبيل المثال، من الأخطاء الشائعة كتابة كود مثل messageCount && <p>New messages</p>. من السهل أن نفترض أنها لا تقوم بعرض أي شيء عندما تكون قيمة messageCount هي 0، ولكنها في الواقع تقوم بعرض الرقم 0 نفسه!

لإصلاح ذلك، قم بتحويل الجانب الأيسر إلى عبارة منطقية (boolean): messageCount > 0 && <p>New messages</p>.

إسناد JSX إلى متغير شرطيًّا

عندما تعيق الاختصارات كتابة الكود، حاول استخدام عبارة if ومتغير. يمكنك إعادة تعيين المتغيرات المعرفة بـ let، لذا ابدأ بتوفير المحتوى الافتراضي الذي تريد عرضه، الاسم:

let itemContent = name;

استخدم عبارة if لإعادة تعيين تعبير JSX إلى itemContent إذا كانت قيمة isPacked صحيحة true.

if (isPacked) {
itemContent = name + " ✔";
}

الأقواس المنحنية تفتح ”نافذة إلى JavaScript“. قم بتضمين المتغير بواسطة الأقواس المنحنية في شجرة JSX المُرجَعة، مدمجًا التعبير المجهز سابقا داخل JSX:

<li className="item">
{itemContent}
</li>

هذا النمط هو الأكثر تفصيلاً، ولكنه أيضًا الأكثر مرونة. وإليك كيف يتم تطبيقه عمليًا:

function Item({ name, isPacked }) {
  let itemContent = name;
  if (isPacked) {
    itemContent = name + " ✔";
  }
  return (
    <li className="item">
      {itemContent}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

كما هو الحال من قبل، لا يعمل هذا فقط مع النصوص ولكن أيضًا لأي JSX تريده:

function Item({ name, isPacked }) {
  let itemContent = name;
  if (isPacked) {
    itemContent = (
      <del>
        {name + " ✔"}
      </del>
    );
  }
  return (
    <li className="item">
      {itemContent}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

إذا لم تكن معتادًا على استخدام JavaScript، فإن هذا التنوع في الأنماط قد يبدو مُرهِقًا في البداية. ومع ذلك، ستساعدك معرفة هذه الأنماط على قراءة وكتابة أي كود JavaScript - وليس فقط مكونات React! اختر الأسلوب الذي تفضله كبداية، وعُد لهذا المرجع مرة أخرى إذا نسيت كيفية عمل الأساليب الأخرى.

Recap

  • في React، يمكنك التحكم في منطق التفريع باستخدام JavaScript.
  • يمكنك إرجاع تعبير JSX شرطيًا باستخدام عبارة if.
  • يمكنك حفظ تعبير JSX شرطيًا في متغير ومن ثم تضمينه داخل تعبير JSX آخر باستخدام الأقواس المنحنية.
  • في JSX، {cond ? <A /> : <B />} تعني ”إذا cond, اعرض <A />, وإلا قم بعرض <B />.
  • في JSX، {cond && <A />} تعني ”إذا cond، اعرض <A />، وإلا لا تقم بعرض أي شيء“.
  • الاختصارات شائعة، ولكنك لست مضطر استخدامها إذا كنت تفضل استخدام if.

Challenge 1 of 3:
عرض أيقونة للعناصر غير المكتملة باستخدام ? :

استخدم العامل الشرطي (cond ? a : b) لعرض ❌ إذا لم تكن قيمة isPacked صحيحة true.

function Item({ name, isPacked }) {
  return (
    <li className="item">
      {name} {isPacked && '✔'}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}