{"id":"l-rf-2-4","courseId":"react-fundamentals","lang":"ar","kind":"lesson","summary":"اعرض أجزاء الواجهة وأخفِها وبدّل بينها بحسب البيانات باستخدام الـ return المبكر والمعامل الثلاثي و&amp;&amp;، مع تجنّب خطأ الصفر الشارد والشروط المتداخلة غير المقروءة.","html":"<p>الواجهات الحقيقية يتغيّر شكلها مع البيانات. يعرض Watchlist شارة «Watched» على بعض الأفلام دون غيرها، ورسالة مشجّعة حين تكون القائمة فارغة، وزر Add معطّلًا حتى تكتب عنوانًا. لا شيء من هذا يحتاج إلى صياغة خاصة في React. إنها JavaScript عادية تقرّر أي JSX تُرجع، وهناك ثلاث أدوات لذلك.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">الـ return المبكر: بدائل كاملة</h2>\n<p>حين يعرض الـ component شيئًا مختلفًا تمامًا في حالة ما، عالج تلك الحالة أولًا ثم أرجِع:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"jsx\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">src/components/MovieList.jsx</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">export</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> default</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> function</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> MovieList</span><span style=\"color:#953800;--shiki-dark:#FFA657\">({ movies }) </span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">{</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  if</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (movies.</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">length</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> ===</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    return</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">p</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> className</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"empty\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>Nothing to watch yet. Add a movie above.&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">p</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  }</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  return</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">ul</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">      {</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">movies.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">map</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">((</span><span style=\"color:#953800;--shiki-dark:#FFA657\">movie</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=></span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">        &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">li</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> key</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">={</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">movie.id</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">{</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">movie.title</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">li</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">      ))</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    &#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">ul</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  );</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p>تُعالَج الحالة الفارغة في سطرين، ولا يهتمّ بقية الدالة إلا بالحالة العادية. هذا هو النمط الأسهل قراءة، فابدأ به أولًا. (الـ <code dir=\"ltr\">map</code> والـ <code dir=\"ltr\">key</code> موضوع الدرس التالي.)</p>\n<p>ويمكن للـ component أيضًا أن يُرجع <code dir=\"ltr\">null</code> كي لا يعرض شيئًا على الإطلاق:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"jsx\" data-index=\"1\"><div class=\"code-head\"><span class=\"code-title\">JSX</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">function</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> WatchedBadge</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">({ </span><span style=\"color:#953800;--shiki-dark:#FFA657\">watched</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> }) {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  if</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">!</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">watched) </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">return</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> null</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  return</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">span</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> className</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"badge\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>Watched&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">span</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<h2 id=\"sec-2\" tabindex=\"-1\">المعامل الثلاثي: هذا أو ذاك</h2>\n<p>داخل JSX، حيث لا يمكنك كتابة <code dir=\"ltr\">if</code>، استخدم المعامل الشرطي للاختيار بين مخرجين:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"jsx\" data-index=\"2\"><div class=\"code-head\"><span class=\"code-title\">JSX</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">p</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> className</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"status\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  {</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">movie.watched </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">?</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> 'Watched'</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> :</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> 'To watch'</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">p</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span></code></pre></div>\n<p>ويعمل مع العناصر أيضًا: <code dir=\"ltr\">{isEditing ? &lt;TitleInput /&gt; : &lt;h2&gt;{title}&lt;/h2&gt;}</code>. أبقِ المعاملات الثلاثية قصيرة. وحين تضع معاملًا ثلاثيًا داخل آخر، أو يمتدّ كل فرع إلى عدّة أسطر، انقل القرار إلى متغيّر فوق <code dir=\"ltr\">return</code>، أو إلى component صغير خاص به.</p>\n<h2 id=\"sec-3\" tabindex=\"-1\">الـ <code dir=\"ltr\">&amp;&amp;</code>: شيء أو لا شيء</h2>\n<p>حين يكون البديل «لا شيء»، يكون معامل AND المنطقي أقصر من معامل ثلاثي مع <code dir=\"ltr\">null</code>:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"jsx\" data-index=\"3\"><div class=\"code-head\"><span class=\"code-title\">JSX</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">li</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  {</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">movie.title</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  {</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">movie.watched </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">&#x26;&#x26;</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">span</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> className</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"badge\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>Watched&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">span</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">li</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span></code></pre></div>\n<p>تحسب JavaScript التعبير <code dir=\"ltr\">a &amp;&amp; b</code> على أنه <code dir=\"ltr\">a</code> إن كانت <code dir=\"ltr\">a</code> قيمة falsy، وإلا فهو <code dir=\"ltr\">b</code>. حين تكون <code dir=\"ltr\">movie.watched</code> قيمتها <code dir=\"ltr\">false</code>، يصبح التعبير <code dir=\"ltr\">false</code>، ولا تعرض React شيئًا مقابل <code dir=\"ltr\">false</code>. وحين تكون <code dir=\"ltr\">true</code>، تحصل على الشارة.</p>\n<aside class=\"callout callout-mistake\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\"/><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/></svg><span><span class=\"callout-kind\">خطأ شائع</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>الصفر الشارد</span></p>\n<p>يبدو <code dir=\"ltr\">{movies.length &amp;&amp; &lt;MovieList movies={movies} /&gt;}</code> صحيحًا، لكن حين تكون القائمة فارغة، يصبح <code dir=\"ltr\">0 &amp;&amp; …</code> يساوي <code dir=\"ltr\">0</code>، وReact تعرض الأرقام. فتعرض صفحتك «0» وحيدًا. اجعل الطرف الأيسر قيمة منطقية حقيقية: <code dir=\"ltr\">{movies.length &gt; 0 &amp;&amp; …}</code>. والفخّ نفسه ينتظر أي رقم على يسار <code dir=\"ltr\">&amp;&amp;</code>، مثل عدد أو index.</p>\n</aside>\n<h2 id=\"sec-4\" tabindex=\"-1\">الشروط في الخصائص</h2>\n<p>الشروط لا تخصّ العناصر الكاملة فقط، فالخصائص تأخذ تعبيرات أيضًا:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"jsx\" data-index=\"4\"><div class=\"code-head\"><span class=\"code-title\">JSX</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">li</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> className</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">={</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">movie.watched </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">?</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> 'movie movie-watched'</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> :</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> 'movie'</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  {</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">movie.title</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">li</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">button</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> disabled</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">={</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">title.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">trim</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">() </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">===</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> ''</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>Add&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">button</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">button</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> aria-pressed</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">={</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">filter </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">===</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> 'watched'</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>Watched&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">button</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span></code></pre></div>\n<p>الثالثة مهمّة لإمكانية الوصول (accessibility): تُخبر <code dir=\"ltr\">aria-pressed</code> مستخدمي الـ screen reader أي زر تبديل هو النشط، وهو ما لا يكفي تغيير اللون وحده لإيصاله. وحين تكون قيمة خاصية منطقية مثل <code dir=\"ltr\">disabled</code> هي <code dir=\"ltr\">false</code> أو <code dir=\"ltr\">null</code>، لا تضعها React على العنصر.</p>\n<h2 id=\"sec-5\" tabindex=\"-1\">اختيار الأداة المناسبة</h2>\n<p>الأنماط الثلاثة تُنتج النوع نفسه من النتائج، فالاختيار مسألة سهولة قراءة. هذه قاعدة عامة تصمد جيدًا في مراجعات الكود:</p>\n<ul>\n<li><strong>المخرجات كلها تتغيّر</strong> (تحميل، خطأ، فراغ، عادي): return مبكر، حالة واحدة في كل مرة، من الأعلى إلى الأسفل.</li>\n<li><strong>موضع واحد يتبدّل بين شيئين</strong>: معامل ثلاثي، بسطر أو اثنين لكل فرع.</li>\n<li><strong>موضع واحد إمّا موجود وإمّا لا</strong>: <code dir=\"ltr\">&amp;&amp;</code> مع قيمة منطقية حقيقية على اليسار.</li>\n</ul>\n<p>حين تلاحظ أنك تكتب معاملًا ثلاثيًا داخل آخر، أو سلسلة <code dir=\"ltr\">&amp;&amp;</code> بثلاثة شروط، توقّف وامنح المنطق اسمًا. إمّا أن تحسب متغيّرًا (<code dir=\"ltr\">const status = …</code>) فوق <code dir=\"ltr\">return</code>، وإمّا أن تستخرج component صغيرًا مثل <code dir=\"ltr\">WatchedBadge</code> يُخفي القرار بداخله. عندها يُقرأ الأب كجملة: عنوان، شارة، أزرار.</p>\n<p>والترتيب مهمّ مع الـ return المبكر أيضًا. ضع أولًا الحالات التي تجعل البقية مستحيلة. إذا كانت قائمة الأفلام قد تكون قيد التحميل أو فاشلة أو فارغة، فافحصها بهذا الترتيب، كي لا يتعامل الـ <code dir=\"ltr\">return</code> الأخير إلا مع بيانات حقيقية.</p>\n<h2 id=\"sec-6\" tabindex=\"-1\">عدم العرض مقابل الإخفاء</h2>\n<p>هناك فرق مهمّ بين هذين:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"jsx\" data-index=\"5\"><div class=\"code-head\"><span class=\"code-title\">JSX</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">{showWatched </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">&#x26;&#x26;</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">WatchedPanel</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> />}</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">div</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> hidden</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">={!</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">showWatched</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">WatchedPanel</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> /></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">div</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span></code></pre></div>\n<p>الأول يزيل <code dir=\"ltr\">WatchedPanel</code> من الشجرة حين يكون الشرط false. تُلغي React <strong>تركيبه (unmount)</strong>: يذهب الـ DOM الخاص به، ويُهدم أي state بداخله، مثل النص المكتوب في حقل. وحين يعود، يبدأ من الصفر. أمّا الثاني فيُبقيه مركّبًا ولا يُخفي إلا غلافه (الخاصية <code dir=\"ltr\">hidden</code> في HTML تعمل مثل <code dir=\"ltr\">display: none</code>)، فيبقى الـ state.</p>\n<p>في أغلب الأحيان تريد الأول؛ لا داعي لإبقاء واجهة غير مرئية حيّة. اختر الإخفاء حين يتوقّع المستخدم أن يبقى عمله الجاري داخل الجزء المخفي، كما في التبويبات التي فيها نماذج نصف معبّأة.</p>\n<aside class=\"callout callout-tip\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5\"/><path d=\"M9 18h6\"/><path d=\"M10 22h4\"/></svg><span><span class=\"callout-kind\">نصيحة</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>سمِّ الشرط</span></p>\n<p><code dir=\"ltr\">{allWatched &amp;&amp; …}</code> أسهل قراءة من <code dir=\"ltr\">{movies.filter((m) =&gt; !m.watched).length === 0 &amp;&amp; …}</code>. احسب قيمة منطقية باسم واضح فوق <code dir=\"ltr\">return</code>، وسيبقى الـ JSX مقروءًا.</p>\n</aside>\n<p>في الدرس التالي تعرض قائمة الأفلام كاملة من البيانات باستخدام <code dir=\"ltr\">map</code>، وتتعلّم لماذا تطلب منك React باستمرار <code dir=\"ltr\">key</code>.</p>\n","toc":[{"id":"sec-1","text":"الـ return المبكر: بدائل كاملة","level":2},{"id":"sec-2","text":"المعامل الثلاثي: هذا أو ذاك","level":2},{"id":"sec-3","text":"الـ &&: شيء أو لا شيء","level":2},{"id":"sec-4","text":"الشروط في الخصائص","level":2},{"id":"sec-5","text":"اختيار الأداة المناسبة","level":2},{"id":"sec-6","text":"عدم العرض مقابل الإخفاء","level":2}],"takeaways":["استخدم <code dir=\"ltr\">return</code> مبكرًا للشاشات البديلة الكاملة، والمعامل الثلاثي للاختيار بين شيئين، و<code dir=\"ltr\">&amp;&amp;</code> لشيء أو لا شيء.","يمكن للـ component أن يُرجع <code dir=\"ltr\">null</code> كي لا يعرض شيئًا على الإطلاق.","الكود <code dir=\"ltr\">{count &amp;&amp; &lt;List /&gt;}</code> يعرض 0 حرفيًا حين تكون count صفرًا؛ قارن صراحةً بـ <code dir=\"ltr\">count &gt; 0 &amp;&amp;</code>.","يمكن للشروط أن تتحكّم في الخصائص أيضًا، مثل <code dir=\"ltr\">className</code> و<code dir=\"ltr\">disabled</code> و<code dir=\"ltr\">aria-pressed</code>.","عدم عرض component يزيله ويزيل الـ state الخاص به؛ أمّا إخفاؤه بـ CSS فيُبقي الاثنين."],"further":[{"title":"Conditional Rendering","url":"https://react.dev/learn/conditional-rendering"},{"title":"Logical AND (&&) on MDN","url":"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_AND"}],"quiz":[{"q":"<p>المصفوفة <code dir=\"ltr\">movies</code> فارغة. ماذا يعرض <code dir=\"ltr\">&lt;div&gt;{movies.length &amp;&amp; &lt;MovieList movies={movies} /&gt;}&lt;/div&gt;</code>؟</p>","options":[{"text":"لا شيء على الإطلاق.","why":"هذا ما تريده، لكن <code dir=\"ltr\">&amp;&amp;</code> يُرجع الطرف الأيسر حين تكون قيمته falsy، والطرف الأيسر هنا هو الرقم 0."},{"text":"قائمة فارغة.","why":"لا يُرسم MovieList أبدًا، لأن <code dir=\"ltr\">0 &amp;&amp; …</code> يتوقّف عند 0."},{"text":"خطأ بخصوص عرض رقم.","why":"الأرقام أبناء صالحة في React، ولهذا بالضبط يظهر الـ 0 بدلًا من الخطأ."},{"text":"الحرف “0”.","why":"صحيح. <code dir=\"ltr\">0 &amp;&amp; x</code> تساوي 0، وReact تعرض الأرقام كنص. اكتب <code dir=\"ltr\">movies.length &gt; 0 &amp;&amp; …</code> بدلًا من ذلك."}],"answer":3},{"q":"<p>يجب أن يعرض <code dir=\"ltr\">MovieList</code> رسالة كاملة «Nothing to watch yet» حين تكون القائمة فارغة، ويعرض القائمة في غير ذلك. أيّ بنية هي الأسهل قراءة؟</p>","options":[{"text":"return مبكر: <code dir=\"ltr\">if (movies.length === 0) return &lt;EmptyState /&gt;;</code> يليه الـ markup العادي للقائمة.","why":"صحيح. تُعالَج الحالة الفارغة وينتهي أمرها، ولا يتعامل بقية الدالة إلا مع الحالة العادية، بلا تداخل."},{"text":"معامل ثلاثي يغلّف كل الـ JSX في الـ component، مع معامل ثلاثي آخر متداخل داخله لشارة كل عنصر.","why":"يعمل، لكن المعاملات الثلاثية المتداخلة داخل كتل JSX كبيرة صعبة القراءة وسهلة الكسر عند التعديل."},{"text":"اعرض الاثنين وأخفِ الخاطئ منهما بـ <code dir=\"ltr\">style={{ display: 'none' }}</code>.","why":"تبقى الشجرتان مركّبتين وتعملان، وصار لديك مكانان يجب إبقاؤهما متزامنين. اعرض ما تحتاجه فقط."}],"answer":0},{"q":"<p>يجب ألّا يعرض <code dir=\"ltr\">WatchedBadge</code> شيئًا حين تكون <code dir=\"ltr\">watched</code> قيمتها false. أيّ نسخة تفعل ذلك؟</p>","options":[{"text":"<code dir=\"ltr\">if (!watched) return;</code> ولا شيء آخر لهذه الحالة","why":"الـ <code dir=\"ltr\">return</code> المجرّد يُرجع <code dir=\"ltr\">undefined</code>. يقبله React 19، لكن <code dir=\"ltr\">return null</code> يصرّح بالنية بوضوح، وهو العُرف الذي ستراه في كل مكان."},{"text":"<code dir=\"ltr\">if (!watched) return &lt;&gt;&lt;/&gt;;</code>","why":"الـ fragment الفارغ لا يعرض شيئًا أيضًا، لكنه أكثر ضجيجًا من العُرف <code dir=\"ltr\">return null</code>."},{"text":"<code dir=\"ltr\">if (!watched) return null;</code>","why":"صحيح. إرجاع <code dir=\"ltr\">null</code> هو الطريقة المعيارية والصريحة لكي لا يعرض الـ component شيئًا."},{"text":"<code dir=\"ltr\">if (!watched) return false;</code>","why":"الـ component الذي يُرجع <code dir=\"ltr\">false</code> لا يعرض شيئًا مصادفةً، لكنه يبدو كخطأ. أرجِع <code dir=\"ltr\">null</code>."}],"answer":2},{"q":"<p>تحتوي لوحة «Watched» القابلة للطيّ على حقل نصي. كتب المستخدم ملاحظة، ثم طوى اللوحة عبر <code dir=\"ltr\">{open &amp;&amp; &lt;Panel /&gt;}</code>، ثم فتحها مجددًا. ماذا حدث للملاحظة؟</p>","options":[{"text":"ما زالت موجودة، لأن React تحتفظ بالـ components بعد إزالتها.","why":"لا تحتفظ React بالـ components التي أُزيلت. حين يصبح الشرط false، يُهدم Panel والـ state الخاص به."},{"text":"اختفت، لأن اللوحة أُزيلت من الشجرة ثم رُكّبت من جديد.","why":"صحيح. العرض الشرطي يُلغي التركيب (unmount). إذا كان يجب أن يبقى الـ state، فاحفظه في أب أو أخفِ اللوحة بـ CSS بدلًا من ذلك."},{"text":"ما زالت موجودة، لأن المتصفّح يستعيد قيم الحقول.","why":"استعادة المتصفّح لقيم النماذج تخصّ التنقّل بين الصفحات، لا عُقد DOM أزالتها React وأعادت إنشاءها."}],"answer":1}],"exercise":{"kind":"web","mode":"react","starter":{"jsx":"function MovieList({ movies }) {\n  return (\n    <div>\n      {movies.length && (\n        <ul>\n          {movies.map((movie) => (\n            <li key={movie.id}>\n              {movie.title}\n              <span className=\"badge\">Watched</span>\n            </li>\n          ))}\n        </ul>\n      )}\n    </div>\n  );\n}\n\nconst MOVIES = [\n  { id: 1, title: 'Arrival', watched: true },\n  { id: 2, title: 'Past Lives', watched: false },\n  { id: 3, title: 'Paddington 2', watched: false },\n];\n\nexport default function App() {\n  return (\n    <main>\n      <section id=\"full\">\n        <MovieList movies={MOVIES} />\n      </section>\n      <section id=\"empty\">\n        <MovieList movies={[]} />\n      </section>\n    </main>\n  );\n}\n"},"solution":{"jsx":"function MovieList({ movies }) {\n  if (movies.length === 0) {\n    return <p>Nothing to watch yet.</p>;\n  }\n\n  return (\n    <ul>\n      {movies.map((movie) => (\n        <li key={movie.id}>\n          {movie.title}\n          {movie.watched && <span className=\"badge\">Watched</span>}\n        </li>\n      ))}\n    </ul>\n  );\n}\n\nconst MOVIES = [\n  { id: 1, title: 'Arrival', watched: true },\n  { id: 2, title: 'Past Lives', watched: false },\n  { id: 3, title: 'Paddington 2', watched: false },\n];\n\nexport default function App() {\n  return (\n    <main>\n      <section id=\"full\">\n        <MovieList movies={MOVIES} />\n      </section>\n      <section id=\"empty\">\n        <MovieList movies={[]} />\n      </section>\n    </main>\n  );\n}\n"},"checks":[{"id":"full-list","test":"return $$('#full li').length === 3;"},{"id":"badge-watched","test":"const li = $$('#full li'); const b = li[0] && li[0].querySelector('span'); return !!b && text(b) === 'Watched';"},{"id":"badge-hidden","test":"const li = $$('#full li'); return li.length === 3 && !li[1].querySelector('span') && !li[2].querySelector('span') && !text(li[1]).includes('Watched') && !text(li[2]).includes('Watched');"},{"id":"empty-message","test":"return text('#empty').includes('Nothing to watch yet.') && !$('#empty ul');"},{"id":"no-zero","test":"return !/\\b0\\b/.test(text('#empty'));"}],"title":"الشارات وحالة القائمة الفارغة","prompt":"<p>في <code dir=\"ltr\">MovieList</code> ثلاثة أخطاء. أصلحها بحيث:</p>\n<ol>\n<li>تظهر شارة <strong>Watched</strong> (<code dir=\"ltr\">&lt;span className=&quot;badge&quot;&gt;Watched&lt;/span&gt;</code>) فقط على الأفلام التي قيمة <code dir=\"ltr\">watched</code> فيها <code dir=\"ltr\">true</code>.</li>\n<li>حين تكون <code dir=\"ltr\">movies</code> فارغة، تعرض القائمة الرسالة <strong>Nothing to watch yet.</strong> بدلًا من قائمة.</li>\n<li>لا تُظهر الحالة الفارغة أبدًا <strong>0</strong> شاردًا.</li>\n</ol>\n<p>يرسم <code dir=\"ltr\">App</code> القائمة مرتين، مرة بثلاثة أفلام ومرة بلا أفلام. لا تغيّر <code dir=\"ltr\">App</code>.</p>\n","hints":["انظر إلى قيمة <code dir=\"ltr\">movies.length &amp;&amp; …</code> حين يكون الطول 0.","عالج الحالة الفارغة أولًا بـ return مبكر: <code dir=\"ltr\">if (movies.length === 0) return &lt;p&gt;…&lt;/p&gt;;</code>","للشارة، استخدم <code dir=\"ltr\">{movie.watched &amp;&amp; &lt;span className=&quot;badge&quot;&gt;Watched&lt;/span&gt;}</code>."],"explanation":"<p>يعالج الـ return المبكر القائمة الفارغة بالكامل، فيزيل التعبير <code dir=\"ltr\">movies.length &amp;&amp; …</code> وصفره الشارد بخطوة واحدة. أمّا في الشارة، فالتعبير <code dir=\"ltr\">movie.watched &amp;&amp; &lt;span&gt;…&lt;/span&gt;</code> آمن لأن <code dir=\"ltr\">watched</code> قيمة منطقية: حين تكون <code dir=\"ltr\">false</code> لا تعرض React شيئًا. احتفظ بـ <code dir=\"ltr\">&amp;&amp;</code> للقيم المنطقية؛ وحين يكون الطرف الأيسر رقمًا، قارنه صراحةً (<code dir=\"ltr\">length &gt; 0</code>).</p>\n","checkLabels":{"full-list":"ما زالت القائمة الكاملة تعرض ثلاثة أفلام","badge-watched":"يعرض Arrival (المُشاهَد) شارة Watched","badge-hidden":"لا يعرض Past Lives وPaddington 2 أي شارة","empty-message":"تعرض القائمة الفارغة “Nothing to watch yet.” ولا تحتوي على <ul>","no-zero":"لا يظهر 0 شارد في القائمة الفارغة"}},"words":605,"readMinutes":4}