{"checkpoints":{"s-rf-1":[{"q":"<p>استنسخ زميلك مستودع Watchlist وشغّل <code dir=\"ltr\">npm run dev</code>. فطبعت الطرفية <code dir=\"ltr\">vite: command not found</code>. ماذا يجب أن يفعل؟</p>","options":[{"text":"يثبّت Vite تثبيتًا عامًا (global) بالأمر <code dir=\"ltr\">npm install -g vite</code>.","why":"التثبيت العام يُخفي المشكلة الحقيقية، وقد يشغّل إصدارًا من Vite غير الذي يتوقّعه المشروع."},{"text":"يحذف <code dir=\"ltr\">package-lock.json</code> ويحاول مجددًا.","why":"ملف القفل هو ما يجعل التثبيت قابلًا للتكرار بالنتيجة نفسها. حذفه لا يغيّر شيئًا في المجلد المفقود."},{"text":"يشغّل <code dir=\"ltr\">npm install</code> أولًا، لأن <code dir=\"ltr\">node_modules</code> لا يُخزَّن في Git.","why":"صحيح. يقرأ <code dir=\"ltr\">npm install</code> ملف package.json وملف القفل ويثبّت Vite محليًا، وهو ما يستخدمه <code dir=\"ltr\">npm run dev</code>."},{"text":"يعيد تسمية <code dir=\"ltr\">index.html</code> حتى يجده Vite.","why":"يجد Vite ملف index.html في جذر المشروع أصلًا. الأمر نفسه هو المفقود، لا ملف الدخول."}],"answer":2},{"q":"<p>يعرض Vite الرسالة «Adjacent JSX elements must be wrapped in an enclosing tag» لهذا الـ component. أيّ إصلاح صحيح؟</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"jsx\" data-index=\"0\"><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\">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\"> App</span><span style=\"color:#953800;--shiki-dark:#FFA657\">() </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\"> (</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">h1</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>Watchlist&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">h1</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\">p</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>3 to watch&#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 style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n","options":[{"text":"غلّف العنصرين بـ fragment <code dir=\"ltr\">&lt;&gt;…&lt;/&gt;</code> أو بعنصر له معنى مثل <code dir=\"ltr\">&lt;header&gt;</code>.","why":"صحيح. الـ component يُرجع جذرًا واحدًا، والـ fragment يجمع الإخوة من دون إضافة عقدة إلى الـ DOM."},{"text":"احذف الأقواس حول الـ JSX.","why":"الأقواس تحمي جملة الـ return متعدّدة الأسطر فقط. ومن دونها لا تُرجع الدالة شيئًا مفيدًا."},{"text":"ضع فاصلة بين العنصرين.","why":"الفاصلة تُنشئ comma expression في JavaScript لا يُرجع إلا العنصر الأخير، وهذا أيضًا ليس ما تريده."},{"text":"قسّم الإرجاع إلى جملتي <code dir=\"ltr\">return</code>.","why":"تتوقّف الدالة عند أول <code dir=\"ltr\">return</code>، فلن يُعرض العنصر الثاني أبدًا."}],"answer":0},{"q":"<p>قيمة <code dir=\"ltr\">count</code> هي 0 وقيمة <code dir=\"ltr\">watched</code> هي <code dir=\"ltr\">true</code>. ما النص الذي يعرضه <code dir=\"ltr\">&lt;p&gt;{count} {watched}&lt;/p&gt;</code>؟</p>","options":[{"text":"“0 true”","why":"لا تعرض React القيم المنطقية كنص. والقيمة <code dir=\"ltr\">true</code> لا تُنتج شيئًا."},{"text":"لا شيء على الإطلاق، لأن القيمتين كلتيهما تُتخطّيان.","why":"القيم المنطقية تُتخطّى، لكن الأرقام تُعرض دائمًا، بما فيها 0."},{"text":"خطأ، لأن القيم المنطقية ليست أبناء صالحة.","why":"القيم المنطقية أبناء صالحة؛ لكنها لا تعرض شيئًا، وهذا ما يجعل <code dir=\"ltr\">&amp;&amp;</code> يعمل."},{"text":"“0” (تليها مسافة)، لأن الأرقام تُعرض والقيم المنطقية لا تعرض شيئًا.","why":"صحيح. الـ 0 رقم فيظهر كنص؛ أمّا <code dir=\"ltr\">true</code> فتُتجاهل."}],"answer":3},{"q":"<p>يحتوي <code dir=\"ltr\">src/components/MovieCard.jsx</code> على <code dir=\"ltr\">export function MovieCard() { … }</code> ولا شيء غيره. أيّ استيراد يعمل في App.jsx؟</p>","options":[{"text":"<code dir=\"ltr\">import MovieCard from &quot;./components/MovieCard.jsx&quot;;</code>","why":"من دون أقواس معقوصة تطلب الـ default export، وهذا الملف لا يحتوي عليه، فتكون القيمة undefined."},{"text":"<code dir=\"ltr\">import { MovieCard } from &quot;./components/MovieCard.jsx&quot;;</code>","why":"صحيح. الـ named export يُستورد باسمه داخل أقواس معقوصة."},{"text":"<code dir=\"ltr\">import { MovieCard } from &quot;MovieCard&quot;;</code>","why":"المُعرِّف المجرّد مثل “MovieCard” يُبحث عنه في node_modules. ملفاتك الخاصة تحتاج إلى مسار نسبي."},{"text":"<code dir=\"ltr\">import * from &quot;./components/MovieCard.jsx&quot;;</code>","why":"هذه صياغة غير صحيحة. استيراد الـ namespace يحتاج إلى اسم، مثل <code dir=\"ltr\">import * as Cards from …</code>."}],"answer":1},{"q":"<p>حذف زميل <code dir=\"ltr\">&lt;StrictMode&gt;</code> من main.jsx لأن السجلات تُطبع مرتين أثناء التطوير. ما أفضل ردّ؟</p>","options":[{"text":"أوافق، لأن StrictMode يجعل تطبيق الإنتاج أبطأ مرتين.","why":"لا تأثير لـ StrictMode على نسخ الإنتاج إطلاقًا."},{"text":"أوافق، لأن StrictMode أصبح متوقّفًا (deprecated) في React 19.","why":"الـ StrictMode حالي وموصى به في React 19."},{"text":"أبقِه؛ فالتشغيل المزدوج لا يحدث إلا في التطوير، وغايته كشف الـ render غير النقي ودوال التنظيف المفقودة مبكرًا.","why":"صحيح. السجلات الإضافية ثمن فحص يلتقط أخطاء حقيقية قبل أن يصادفها المستخدمون."},{"text":"أبقِه، لكن غلّف كل component بـ StrictMode خاص به أيضًا.","why":"StrictMode واحد في الجذر يغطّي الشجرة كلها. وإضافة المزيد بالتداخل لا تضيف شيئًا."}],"answer":2}],"s-rf-2":[{"q":"<p>يعرض <code dir=\"ltr\">&lt;MovieCard title=&quot;Arrival&quot; watched=&quot;false&quot; /&gt;</code> شارة «Watched»، والـ component يستخدم <code dir=\"ltr\">{watched &amp;&amp; &lt;Badge /&gt;}</code>. لماذا؟</p>","options":[{"text":"علامات الاقتباس تمرّر النص “false”، وأي نص غير فارغ قيمته truthy. مرّر <code dir=\"ltr\">watched={false}</code> بدلًا من ذلك.","why":"صحيح. لا يُمرَّر بين علامتي اقتباس إلا النصوص؛ أمّا القيم المنطقية والأرقام والكائنات فتحتاج إلى أقواس معقوصة."},{"text":"الـ props المنطقية يجب أن تُكتب دائمًا كخاصية مجرّدة.","why":"الخاصية المجرّدة تعني <code dir=\"ltr\">true</code>. ولتمرير false تكتب <code dir=\"ltr\">watched={false}</code> أو تحذف الـ prop."},{"text":"المعامل <code dir=\"ltr\">&amp;&amp;</code> لا يعمل مع الـ props.","why":"يعمل <code dir=\"ltr\">&amp;&amp;</code> مع أي قيمة. المشكلة في نوع القيمة التي مُرّرت."},{"text":"القيمة الافتراضية في الـ component تتغلّب على الـ prop.","why":"لا تُطبَّق القيم الافتراضية إلا حين يكون الـ prop قيمته undefined. وهنا الـ prop هو النص “false”."}],"answer":0},{"q":"<p>تُعرض القائمة، لكن الـ console يحذّر «Each child in a list should have a unique key prop». أين الخطأ؟</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\"> MovieItem</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>\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\">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>\n<span class=\"line\"></span>\n<span class=\"line\"><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\"> &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">MovieItem</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> movie</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">={</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">movie</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">}</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> />)}</span></span></code></pre></div>\n","options":[{"text":"القيمة <code dir=\"ltr\">movie.id</code> ليست فريدة بما يكفي؛ استخدم الـ index.","why":"المعرّفات سليمة. الـ key ببساطة في المكان الخطأ، والـ index سيزيد أخطاء إعادة الترتيب سوءًا."},{"text":"الـ <code dir=\"ltr\">&lt;ul&gt;</code> حول القائمة يحتاج إلى key.","why":"الـ <code dir=\"ltr\">&lt;ul&gt;</code> عنصر واحد. العناصر التي تُرجعها <code dir=\"ltr\">map</code> هي الإخوة الذين يجب على React التمييز بينهم."},{"text":"الـ keys تعمل على عناصر HTML فقط، لا على الـ components.","why":"الـ keys تعمل على الـ components أيضًا؛ وهذا بالضبط مكان هذا الـ key."},{"text":"يجب أن يوضع الـ key على <code dir=\"ltr\">&lt;MovieItem key={movie.id} … /&gt;</code> داخل <code dir=\"ltr\">map</code>، لا على الـ <code dir=\"ltr\">&lt;li&gt;</code> داخل الـ component.","why":"صحيح. تقرأ React الـ keys من العناصر في المصفوفة، وهي هنا عناصر MovieItem."}],"answer":3},{"q":"<p>تبني <code dir=\"ltr\">Dialog</code> له عنوان، وأي محتوى في جسمه، وأزرار تختلف من استخدام لآخر. أيّ واجهة تُبقي Dialog بسيطًا ومرنًا؟</p>","options":[{"text":"prop اسمه <code dir=\"ltr\">buttons</code> فيه مصفوفة من نصوص التسميات، ويُنشئ Dialog الأزرار ومعالجات النقر الخاصة بها.","why":"سيحتاج Dialog إلى معرفة كل إجراء في التطبيق، وتكبر واجهته مع كل استخدام جديد."},{"text":"<code dir=\"ltr\">title</code> كـ prop، والجسم كـ <code dir=\"ltr\">children</code>، وprop اسمه <code dir=\"ltr\">footer</code> يأخذ JSX مثل <code dir=\"ltr\">footer={&lt;button onClick={close}&gt;Close&lt;/button&gt;}</code>.","why":"صحيح. يملك Dialog الإطار ويحدّد مواضع الـ slots؛ والمستدعون يقرّرون ما يوضع فيها."},{"text":"component Dialog خاص بكل استخدام، يُنسخ ويُعدَّل في كل مرة.","why":"النسخ تتباعد مع الوقت، وكل إصلاح في التنسيق يجب تكراره في كل نسخة."},{"text":"مرّر الـ markup الكامل للنافذة كنص HTML.","why":"نصوص HTML تتجاوز الـ components والتهريب في React، وهي غير آمنة مع أي بيانات من المستخدم."}],"answer":1},{"q":"<p>لدى فيلم <code dir=\"ltr\">genres: [&quot;drama&quot;, &quot;sci-fi&quot;]</code>، ولا تتكرّر الأنواع داخل الفيلم الواحد. ما الـ key الجيد عند عرضها؟</p>","options":[{"text":"<code dir=\"ltr\">Math.random()</code>، حتى تكون الـ keys فريدة دائمًا.","why":"الـ key الجديد في كل render يجبر React على إعادة إنشاء كل عنصر في كل render."},{"text":"الـ index، لأن القائمة قصيرة.","why":"القوائم القصيرة قد يتغيّر ترتيبها أيضًا. وحين توجد قيمة فريدة وثابتة، فضّلها."},{"text":"نص النوع نفسه، لأنه فريد داخل القائمة وثابت.","why":"صحيح. لا يلزم أن تكون الـ keys إلا فريدة بين الإخوة وثابتة مع الوقت، والنص يحقّق الأمرين."},{"text":"بلا key، لأن النصوص لا تحتاج إلى keys.","why":"كل عنصر تُرجعه <code dir=\"ltr\">map</code> يحتاج إلى key، أيًّا كانت البيانات التي جاء منها."}],"answer":2},{"q":"<p>يجب أن يعرض الـ component المسمّى <code dir=\"ltr\">MovieTitle</code> الـ prop المسمّى <code dir=\"ltr\">title</code> بأحرف كبيرة. أيّ نسخة صحيحة؟</p>","options":[{"text":"<code dir=\"ltr\">const upper = title.toUpperCase(); return &lt;h2&gt;{upper}&lt;/h2&gt;;</code>","why":"صحيح. اشتقّ قيمة جديدة من الـ prop أثناء الـ render واترك الـ prop نفسه كما هو."},{"text":"<code dir=\"ltr\">props.title = props.title.toUpperCase(); return &lt;h2&gt;{props.title}&lt;/h2&gt;;</code>","why":"هذا يكتب في الـ props، وهي ملك للأب. وتجمّد React الـ props في وضع التطوير، فيرمي خطأ."},{"text":"<code dir=\"ltr\">const [upper] = useState(title.toUpperCase());</code> ثم اعرض <code dir=\"ltr\">upper</code>.","why":"لا يقرأ الـ state قيمته الابتدائية إلا مرة واحدة، فسيتجاهل العنوان التغييرات اللاحقة."},{"text":"<code dir=\"ltr\">useEffect(() =&gt; setUpper(title.toUpperCase()), [title]);</code> ثم اعرض <code dir=\"ltr\">upper</code>.","why":"effect مع state من أجل قيمة مشتقّة يضيف render إضافيًا بنص قديم. احسبها أثناء الـ render."}],"answer":0}],"s-rf-3":[{"q":"<p>زر «+1 later» ينفّذ <code dir=\"ltr\">setTimeout(() =&gt; setCount(count + 1), 1000)</code>. نقرته ثلاث مرات خلال ثانية واحدة، وكانت <code dir=\"ltr\">count</code> تساوي 0. كم تصبح بعد انطلاق المؤقّتات؟</p>","options":[{"text":"3، لأن ثلاثة مؤقّتات عملت.","why":"كل مؤقّت احتفظ بقيمة <code dir=\"ltr\">count</code> من الـ render الذي أُنشئ فيه، وكانت 0 في كل مرة."},{"text":"0، لأن الـ state لا يمكن ضبطه من مؤقّت.","why":"ضبط الـ state من مؤقّت لا بأس به؛ إنه يتحدّث فعلًا."},{"text":"خطأ بسبب ضبط الـ state خارج معالج أحداث.","why":"تسمح React بتحديثات الـ state من المؤقّتات والـ promises والمعالجات على حدّ سواء."},{"text":"1، لأن كل مؤقّت حسب 0 + 1. استخدم <code dir=\"ltr\">setCount((c) =&gt; c + 1)</code> لتحصل على 3.","why":"صحيح. دالة التحديث تستقبل أحدث قيمة بدل لقطة قديمة."}],"answer":3},{"q":"<p>الدالة <code dir=\"ltr\">handleRemove</code> تنفّذ <code dir=\"ltr\">const i = movies.findIndex((m) =&gt; m.id === id); movies.splice(i, 1); setMovies(movies);</code>. لكن الفيلم لا يختفي. لماذا؟</p>","options":[{"text":"تُرجع <code dir=\"ltr\">findIndex</code> القيمة -1 لكل فيلم.","why":"إنها تجد الـ index بشكل صحيح. المشكلة تأتي بعد ذلك."},{"text":"غيّرت <code dir=\"ltr\">splice</code> المصفوفة الموجودة في مكانها، وأُعيدت المصفوفة نفسها، فلم ترَ React أي تغيير.","why":"صحيح. تقارن React باستخدام Object.is. أنشئ مصفوفة جديدة: <code dir=\"ltr\">setMovies(movies.filter((m) =&gt; m.id !== id))</code>."},{"text":"يجب أن تستدعي <code dir=\"ltr\">setMovies</code> قبل تغيير المصفوفة.","why":"الترتيب لا يفيد. أي تعديل على المصفوفة الموجودة يترك React مع المرجع نفسه."},{"text":"لا يمكن تخزين المصفوفات في الـ state.","why":"المصفوفات نوع طبيعي من الـ state؛ لكن يجب استبدالها، لا تعديلها."}],"answer":1},{"q":"<p>تنقر Add، فيظهر الفيلم الجديد للحظة، ثم يُعاد تحميل الصفحة ويختفي. ما الناقص؟</p>","options":[{"text":"key على عنصر القائمة الجديد.","why":"غياب الـ key يسبّب تحذيرًا في الـ console، لا إعادة تحميل للصفحة."},{"text":"الـ <code dir=\"ltr\">useEffect</code> لحفظ الفيلم.","why":"الحفظ قد يفيد بعد إعادة التحميل، لكن الخطأ الحقيقي أن الصفحة تُعاد تحميلها أصلًا."},{"text":"<code dir=\"ltr\">e.preventDefault()</code> في بداية معالج الإرسال الخاص بالنموذج.","why":"صحيح. من دونها يُجري المتصفّح إرسالًا عاديًا للنموذج ويعيد تحميل الصفحة."},{"text":"الخاصية <code dir=\"ltr\">type=&quot;button&quot;</code> على زر Add.","why":"هذا يمنع الزر من إرسال النموذج كليًا، فلن يعمل Enter ولا معالج الإرسال بعد ذلك."}],"answer":2},{"q":"<p>هذا المؤقّت يعدّ بزيادة 2 كل ثانية أثناء التطوير. ما الإصلاح؟</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:#8250DF;--shiki-dark:#D2A8FF\">useEffect</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:#8250DF;--shiki-dark:#D2A8FF\">  setInterval</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(() </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=></span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\"> setSeconds</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">((</span><span style=\"color:#953800;--shiki-dark:#FFA657\">s</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=></span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> s </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">+</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 1</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">), </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1000</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","options":[{"text":"أرجِع دالة تنظيف: <code dir=\"ltr\">const id = setInterval(…); return () =&gt; clearInterval(id);</code>","why":"صحيح. يركّب StrictMode ثم ينظّف ثم يركّب من جديد؛ ومن دون دالة تنظيف يظل المؤقّت الأول يعمل بجانب الثاني."},{"text":"احذف StrictMode حتى يعمل الـ effect مرة واحدة.","why":"هذا يُخفي الخطأ أثناء التطوير، لكن غياب دالة التنظيف سيظل يُسرّب مؤقّتًا كلما أُلغي تركيب الـ component."},{"text":"أضف <code dir=\"ltr\">seconds</code> إلى مصفوفة الاعتماديات.","why":"هذا سيعيد تشغيل الـ effect كل ثانية، ومع استمرار غياب دالة التنظيف، ستتراكم مؤقّتات أكثر."},{"text":"استخدم <code dir=\"ltr\">setSeconds(seconds + 1)</code> بدل دالة التحديث.","why":"دالة التحديث صحيحة هنا. السرعة المضاعفة سببها مؤقّتان يعملان في الوقت نفسه."}],"answer":0},{"q":"<p>يحتفظ <code dir=\"ltr\">SearchBox</code> بـ <code dir=\"ltr\">query</code> في الـ state الخاص به. ويجب أن يعرض أخوه <code dir=\"ltr\">MovieList</code> فقط الأفلام التي يحتوي عنوانها على نص البحث. ماذا تفعل؟</p>","options":[{"text":"اجعل SearchBox يكتب نص البحث في localStorage، واجعل MovieList يقرؤه في كل render.","why":"لن يعيد MovieList الـ render حين يتغيّر نص البحث، والتخزين أداة خاطئة لمشاركة الـ state."},{"text":"امنح MovieList الـ state الخاص به <code dir=\"ltr\">query</code>، وانسخه من SearchBox بـ effect.","why":"نسختان تُزامَنان بـ effect أبطأ وقد تختلفان. المالك الواحد أبسط."},{"text":"اعرض MovieList داخل SearchBox حتى يستطيع قراءة الـ state.","why":"هذا يلوي بنية الواجهة حول البيانات ويكسر التخطيط."},{"text":"انقل <code dir=\"ltr\">query</code> إلى أبيهما المشترك، ومرّره إلى كليهما، ومرّر معالج تغيير إلى SearchBox.","why":"صحيح. رفع الـ state يمنحه مالكًا واحدًا، ويقرأ الأخوان القيمة نفسها."}],"answer":3}],"s-rf-4":[{"q":"<p>بعد أول deploy لك على Vercel، الموقع فارغ والـ console يعرض 404 للملف <code dir=\"ltr\">/src/main.jsx</code>. ما الخطأ؟</p>","options":[{"text":"قدّم Vercel ملف <code dir=\"ltr\">index.html</code> المصدري بدل نسخة البناء. تحقّق أن الإعداد المسبق لإطار العمل هو Vite وأن مجلد المخرجات هو <code dir=\"ltr\">dist</code>.","why":"صحيح. ملف index.html في الجذر لا يعمل إلا عبر خادم التطوير في Vite. ما يجب تقديمه هو الملفات المبنية في dist/."},{"text":"لم يُدعم React 19 على Vercel بعد.","why":"يقدّم Vercel ملفات ثابتة؛ ولا يهمّه أي إصدار من React بناها."},{"text":"يجب إعادة تسمية <code dir=\"ltr\">main.jsx</code> إلى <code dir=\"ltr\">main.js</code> للإنتاج.","why":"امتداد الملف ليس المشكلة. في البناء الصحيح يُترجم main.jsx إلى حزمة ولا يُطلب أبدًا."},{"text":"يحتاج التطبيق إلى rewrite في <code dir=\"ltr\">vercel.json</code> نحو <code dir=\"ltr\">/src/main.jsx</code>.","why":"الإشارة إلى ملفات المصدر ستفشل أيضًا؛ فالمتصفّحات لا تستطيع تشغيل JSX."}],"answer":0},{"q":"<p>يجب أن يكون الزر بلون indigo حين تكون <code dir=\"ltr\">active</code> قيمتها true. أيّ className يعمل بموثوقية مع Tailwind؟</p>","options":[{"text":"<code dir=\"ltr\">`bg-${active ? &quot;indigo&quot; : &quot;slate&quot;}-600`</code>","why":"لا يرى Tailwind أسماء الـ classes كاملة أبدًا، فلا تُولَّد أيٌّ من الخلفيتين."},{"text":"<code dir=\"ltr\">active ? &quot;bg-indigo-600 text-white&quot; : &quot;bg-slate-100&quot;</code>","why":"صحيح. اسما الـ classes الكاملان يظهران في المصدر، فيولّدهما Tailwind."},{"text":"التعبير <code dir=\"ltr\">&quot;bg-&quot; + color + &quot;-600&quot;</code> مع <code dir=\"ltr\">color</code> قادمة من الـ props","why":"بناء الأسماء من قطع له المشكلة نفسها: الـ classes الكاملة لا تظهر أبدًا في المصدر."},{"text":"<code dir=\"ltr\">style={{ className: &quot;bg-indigo-600&quot; }}</code>","why":"الـ <code dir=\"ltr\">className</code> ليست خاصية CSS، فلا يضبط هذا أي شيء."}],"answer":1},{"q":"<p>في Watchlist المكتمل، أيّ قيمة يجب ألّا تُخزَّن في <code dir=\"ltr\">useState</code>؟</p>","options":[{"text":"مصفوفة الأفلام.","why":"تتغيّر الأفلام حين يضيفها المستخدم أو يبدّل حالتها أو يحذفها، فهي state حقيقي."},{"text":"الفلتر المختار.","why":"يتغيّر الفلتر حين ينقر المستخدم زر فلترة، ولا يمكن حسابه من أي شيء آخر."},{"text":"عدد الأفلام غير المُشاهَدة.","why":"صحيح. إنه مشتقّ من الأفلام أثناء الـ render، وتخزينه لا يُنشئ إلا نسخة قد تصبح قديمة."},{"text":"النص المكتوب في نموذج الإضافة، داخل AddMovieForm.","why":"يتغيّر نص المسوّدة أثناء الكتابة ويعيش في النموذج. إنه state حقيقي."}],"answer":2},{"q":"<p>تريد إرسال pull request فيه شريط فلترة بتنسيق جديد، وتدع صديقًا يفحصه على هاتفه قبل أن يصبح حيًّا. ماذا يعطيك Vercel؟</p>","options":[{"text":"لا شيء حتى تعمل merge، لأن main وحده يُبنى.","why":"مع التكامل مع Git، كل branch يُرفع يُبنى."},{"text":"deploy إنتاج للـ branch، يحلّ محلّ الموقع الحيّ.","why":"لا يتغيّر الإنتاج إلا من branch الإنتاج."},{"text":"ملف ZIP للنسخة المبنية ترسله إلى صديقك.","why":"ينشر Vercel النسخ المبنية على روابط؛ ومشاركة الملفات ليست جزءًا من مسار العمل."},{"text":"preview deployment برابط خاص به، يُنشر على الـ pull request.","why":"صحيح. روابط المعاينة تتيح لأي أحد فحص تغيير من دون لمس الإنتاج."}],"answer":3},{"q":"<p>أيّ جزء من كود Watchlist مكانه effect؟</p>","options":[{"text":"كتابة الأفلام في localStorage كلما تغيّرت.","why":"صحيح. إبقاء نظام خارجي متزامنًا مع الـ state هو بالضبط وظيفة الـ effects."},{"text":"حساب قائمة الأفلام الظاهرة من الفلتر.","why":"هذه بيانات مشتقّة. احسبها أثناء الـ render."},{"text":"مسح حقل العنوان بعد أن يرسل المستخدم النموذج.","why":"هذا ناتج عن إجراء محدّد، فمكانه معالج الإرسال."},{"text":"إضافة فيلم حين يُرسل النموذج.","why":"إجراءات المستخدم تُعالَج في معالجات الأحداث، لا في الـ effects."}],"answer":0}]},"final":[{"q":"<p>يزيد component متغيّرًا اسمه <code dir=\"ltr\">renderCount</code> في مستوى الـ module داخل جسمه ويعرضه. الرقم مختلف بين التطوير والإنتاج. لماذا؟</p>","options":[{"text":"يخزّن Vite الـ modules مؤقّتًا بطريقة مختلفة في الإنتاج.","why":"التخزين المؤقّت للـ modules لا يغيّر عدد المرات التي تستدعي فيها React الـ component."},{"text":"الـ component غير نقي: يرسمه StrictMode مرتين أثناء التطوير، فيُنفَّذ الأثر الجانبي مرتين.","why":"صحيح. يجب ألّا يغيّر الـ render أي شيء خارج الـ component. انقل الآثار الجانبية إلى المعالجات أو الـ effects."},{"text":"نسخ الإنتاج تحذف المتغيّرات في مستوى الـ module.","why":"متغيّرات الـ module ما زالت موجودة في الإنتاج؛ عدد مرّات الـ render وحده هو المختلف."},{"text":"يرسم React 19 كل component مرتين في الإنتاج.","why":"الإنتاج يرسم مرة واحدة. الرسم المزدوج فحص خاص بالتطوير فقط."}],"answer":1},{"q":"<p>أيّ تعبير يعرض النص «Watched» فقط حين تكون <code dir=\"ltr\">movie.watched</code> قيمتها true، ولا شيء في غير ذلك؟</p>","options":[{"text":"<code dir=\"ltr\">{movie.watched ? &quot;Watched&quot;}</code>","why":"المعامل الثلاثي يحتاج إلى الفرعين كليهما؛ هذا خطأ في الصياغة."},{"text":"<code dir=\"ltr\">{if (movie.watched) &quot;Watched&quot;}</code>","why":"الـ <code dir=\"ltr\">if</code> جملة ولا يمكن وضعها داخل أقواس JSX المعقوصة."},{"text":"<code dir=\"ltr\">{movie.watched &amp;&amp; &quot;Watched&quot;}</code>","why":"صحيح. حين تكون <code dir=\"ltr\">watched</code> قيمتها false يصبح التعبير false، ولا تعرض React شيئًا مقابل false."},{"text":"<code dir=\"ltr\">{movie.watched || &quot;Watched&quot;}</code>","why":"المعامل <code dir=\"ltr\">||</code> يُرجع “Watched” حين تكون watched قيمتها false، أي عكس ما تريده، ولا يعرض شيئًا مرئيًا حين تكون true."}],"answer":2},{"q":"<p>تكتب في حقل داخل صف من قائمة، فيفقد التركيز بعد كل ضغطة مفتاح. والقائمة تستخدم <code dir=\"ltr\">key={Math.random()}</code>. ما الذي يحدث؟</p>","options":[{"text":"كل render ينتج keys جديدة، فتعامل React كل صف كأنه جديد، وتهدمه وتُنشئ حقلًا جديدًا.","why":"صحيح. يجب أن تكون الـ keys ثابتة. استخدم معرّفًا مخزّنًا مع كل عنصر."},{"text":"لا يمكن التحكّم في الحقول داخل القوائم.","why":"الـ controlled inputs تعمل في القوائم. الـ key المتغيّر هو ما يعيد تركيب الصف."},{"text":"قد تنتج <code dir=\"ltr\">Math.random()</code> keys مكرّرة.","why":"التكرار ممكن لكنه نادر. المشكلة الحقيقية أن الـ keys تتغيّر في كل render."},{"text":"تضع React حدًّا لعدد مرّات إعادة render القائمة.","why":"لا يوجد حدّ كهذا. يُعاد إنشاء الصفوف لأن هويتها تتغيّر."}],"answer":0},{"q":"<p>داخل معالج نقرة تستدعي <code dir=\"ltr\">setFilter(&quot;watched&quot;)</code> ثم <code dir=\"ltr\">console.log(visible.length)</code>، حيث <code dir=\"ltr\">visible</code> مشتقّة من <code dir=\"ltr\">filter</code> أثناء الـ render. ماذا يُطبع؟</p>","options":[{"text":"عدد الأفلام المُشاهَدة.","why":"الفلتر الجديد يُطبَّق في الـ render التالي. وهذا المعالج ما زال يرى <code dir=\"ltr\">visible</code> القديمة."},{"text":"0، لأن الـ state يُعاد ضبطه أثناء التحديث.","why":"التحديث لا يعيد ضبط الـ state أبدًا؛ تبقى اللقطة القديمة سليمة حتى الـ render التالي."},{"text":"خطأ، لأن القيم المشتقّة لا يمكن قراءتها في المعالجات.","why":"تستطيع المعالجات قراءة أي شيء من الـ render الخاص بها. إنها فقط تقرأ قيم ذلك الـ render."},{"text":"الطول من الـ render الحالي، بناءً على الفلتر القديم.","why":"صحيح. كل render لقطة؛ والقيمة الجديدة تظهر في الـ render التالي."}],"answer":3},{"q":"<p>يخزّن Watchlist القيمة <code dir=\"ltr\">visibleMovies</code> في الـ state ويحدّثها حين يتغيّر الفلتر. الأفلام المضافة حديثًا لا تظهر حتى يُنقر الفلتر من جديد. ما أفضل إصلاح؟</p>","options":[{"text":"حدّث <code dir=\"ltr\">visibleMovies</code> أيضًا في معالج الإضافة.","why":"هذا يرقّع حالة واحدة. سيحتاج التبديل والحذف إلى الإصلاح نفسه، وستنساه الميزة التالية."},{"text":"احذف الـ state المسمّى <code dir=\"ltr\">visibleMovies</code> واحسبه أثناء الـ render من <code dir=\"ltr\">movies</code> و<code dir=\"ltr\">filter</code>.","why":"صحيح. القيمة المشتقّة المحسوبة في كل render متزامنة دائمًا مع مصادرها."},{"text":"زامنها بـ effect يعتمد على <code dir=\"ltr\">movies</code> و<code dir=\"ltr\">filter</code>.","why":"ينجح بعد render إضافي ببيانات قديمة، ويُبقي الـ state المكرّر غير الضروري."},{"text":"خزّن الفلتر داخل كل كائن فيلم.","why":"الفلتر خاصية من خصائص العرض، لا من خصائص كل فيلم. وهذا يجعل التحديثات أصعب."}],"answer":1},{"q":"<p>بمجرّد تحميل الصفحة، تبلّغ React بالخطأ «Too many re-renders». عناصر القائمة تحتوي على <code dir=\"ltr\">&lt;button onClick={handleRemove(movie.id)}&gt;Remove&lt;/button&gt;</code>. ما الإصلاح؟</p>","options":[{"text":"غلّف <code dir=\"ltr\">handleRemove</code> بـ <code dir=\"ltr\">useEffect</code>.","why":"التعامل مع الأحداث ليس effect. المشكلة أن المعالج يُستدعى أثناء الـ render."},{"text":"غيّره إلى <code dir=\"ltr\">onClick={handleRemove}</code> واقرأ المعرّف من الحدث.","why":"ستمرّر React حدث النقر، لا المعرّف، فلن يحذف المعالج شيئًا."},{"text":"مرّر دالة: <code dir=\"ltr\">onClick={() =&gt; handleRemove(movie.id)}</code>.","why":"صحيح. لا تُنفَّذ الـ arrow function إلا عند النقر، ثم تستدعي المعالج بالمعرّف الصحيح."},{"text":"استخدم <code dir=\"ltr\">onMouseUp</code> بدل <code dir=\"ltr\">onClick</code>.","why":"أي prop لحدث له المشكلة نفسها حين يُعطى نتيجة استدعاء بدل دالة."}],"answer":2},{"q":"<p>كُتب مربّع اختيار «Watched» بالشكل <code dir=\"ltr\">&lt;input type=&quot;checkbox&quot; value={watched} onChange={(e) =&gt; setWatched(e.target.value)} /&gt;</code>. النقر عليه لا يُظهر علامة الاختيار أبدًا. ما الخطأ؟</p>","options":[{"text":"لا يمكن التحكّم في مربّعات الاختيار في React.","why":"يمكن ذلك؛ لكنها تستخدم خاصية مختلفة."},{"text":"يحتاج المعالج إلى <code dir=\"ltr\">e.preventDefault()</code>.","why":"منع السلوك الافتراضي سيوقف تبديل مربّع الاختيار كليًا."},{"text":"يجب أن تكون <code dir=\"ltr\">watched</code> نصًا.","why":"القيمة المنطقية هي النوع الصحيح لمربّع الاختيار. المشكلة في الخاصية التي تُقرأ وتُضبط."},{"text":"مربّعات الاختيار تستخدم <code dir=\"ltr\">checked</code> و<code dir=\"ltr\">e.target.checked</code>، لا <code dir=\"ltr\">value</code>.","why":"صحيح. الـ <code dir=\"ltr\">value</code> هي النص الذي يُرسل مع النموذج؛ أمّا <code dir=\"ltr\">checked</code> فهي حالة التشغيل والإيقاف."}],"answer":3},{"q":"<p>يحمّل Watchlist الأفلام المحفوظة في <code dir=\"ltr\">useEffect(() =&gt; setMovies(load()), [])</code> ويحفظها في effect آخر على <code dir=\"ltr\">[movies]</code>. يبلّغ المستخدمون أن قائمتهم تُمسح أحيانًا عند إعادة التحميل. ما التصميم الأفضل؟</p>","options":[{"text":"حمّل في دالة تهيئة الـ state، <code dir=\"ltr\">useState(load)</code>، ليكون للـ render الأول الأفلامُ المحفوظة أصلًا.","why":"صحيح. مع الـ effect، يحفظ الـ render الأول المصفوفة الابتدائية الفارغة قبل أن يعمل التحميل."},{"text":"ادمج الـ effectين في واحد بلا مصفوفة اعتماديات.","why":"هذا يعمل بعد كل render، وما زال يحفظ قبل التحميل في الـ render الأول."},{"text":"احذف StrictMode حتى تعمل الـ effects مرة واحدة.","why":"مشكلة الترتيب موجودة في الإنتاج أيضًا؛ StrictMode يجعلها أوضح فقط."},{"text":"احفظ باستخدام <code dir=\"ltr\">setTimeout</code> لتمنح التحميل وقتًا لينتهي.","why":"حيل التوقيت تُخفي المشكلة وتفشل على الأجهزة البطيئة. حمّل قبل الـ render الأول بدلًا من ذلك."}],"answer":0},{"q":"<p>يحتفظ <code dir=\"ltr\">AddMovieForm</code> بالعنوان المكتوب في الـ state الخاص به، ويملك <code dir=\"ltr\">App</code> الأفلام. أين يجب أن يعيش منطق «مسح الحقل بعد الإضافة»؟</p>","options":[{"text":"في App، بتمرير prop اسمه <code dir=\"ltr\">clear</code> إلى النموذج.","why":"لا يملك App نص المسوّدة، فلا ينبغي أن يديره."},{"text":"في effect داخل النموذج يراقب قائمة الأفلام.","why":"تتغيّر القائمة أيضًا عند التبديل والحذف، فسيُمسح الحقل في أوقات خاطئة."},{"text":"في معالج الإرسال الخاص بالنموذج، مباشرة بعد استدعاء <code dir=\"ltr\">onAdd</code>.","why":"صحيح. النموذج يملك المسوّدة ويملك إجراء المستخدم الذي يجب أن يمسحها."},{"text":"في MovieList، بعد أن يعرض العنصر الجديد.","why":"لا يعرف MovieList شيئًا عن النموذج، ولا ينبغي أن يمدّ يده إلى الـ state الخاص به."}],"answer":2},{"q":"<p>تريد أن يكون لزر الفلترة النشط تنسيق مختلف، وأنت تضبط أصلًا <code dir=\"ltr\">aria-pressed={value === key}</code> على كل زر. أيّ نهج في Tailwind هو الأنسب؟</p>","options":[{"text":"أضف <code dir=\"ltr\">aria-pressed:bg-indigo-600 aria-pressed:text-white</code> إلى classes الزر.","why":"صحيح. يقرأ الـ variant الخاصية نفسها التي تعلنها الـ screen readers، فيبقى المظهر والدلالة متزامنين."},{"text":"ابنِ الـ class بـ template literal من اسم الفلتر.","why":"لا يستطيع Tailwind اكتشاف الـ classes المبنية من قطع، فلن تُولَّد."},{"text":"أضف <code dir=\"ltr\">useEffect</code> يضبط نمط الزر عبر الـ DOM.","why":"الوصول إلى الـ DOM للتنسيق يتجاوز React ويضيف effect حيث لا حاجة إليه."},{"text":"أنشئ ملف <code dir=\"ltr\">tailwind.config.js</code> فيه لون اسمه <code dir=\"ltr\">active</code>.","why":"لا يحتاج v4 إلى ملف إعدادات، واللون وحده لا يحدّد متى يُطبَّق."}],"answer":0},{"q":"<p>يستدعي تطبيقك API أفلام مدفوعًا باستخدام <code dir=\"ltr\">import.meta.env.VITE_MOVIE_API_SECRET</code>. لماذا هذه مشكلة؟</p>","options":[{"text":"لا يدعم Vite متغيّرات البيئة في الإنتاج.","why":"يدعمها Vite؛ وهذا بالضبط ما يجعل القيمة تدخل الحزمة."},{"text":"يحذف Vercel متغيّرات <code dir=\"ltr\">VITE_</code> من البناء.","why":"يمرّرها Vercel إلى البناء، ويضمّنها Vite."},{"text":"اسم المتغيّر طويل جدًا.","why":"طول الاسم لا علاقة له بالمشكلة. المشكلة هي انكشاف القيمة."},{"text":"قيم <code dir=\"ltr\">VITE_</code> تُضمَّن في حزمة JavaScript العلنية، فيستطيع أي أحد قراءة السرّ.","why":"صحيح. احتفظ بالأسرار على خادم، مثل serverless function، واستدعِه من المتصفّح."}],"answer":3},{"q":"<p>استخرجت component اسمه <code dir=\"ltr\">Card</code> يرسم حدودًا وحشوًا و<code dir=\"ltr\">{children}</code>، واستخدمته لعناصر الأفلام وللحالة الفارغة. ما الفائدة الأساسية؟</p>","options":[{"text":"الـ Cards تُرسم أسرع من الـ divs.","why":"الـ component لا يضيف سرعة في الرسم؛ إنه يرسم العناصر نفسها."},{"text":"يُعرَّف الإطار مرة واحدة، فتحدث تغييرات التنسيق في مكان واحد، ولا يقدّم كل استخدام إلا محتواه.","why":"صحيح. التركيب باستخدام children يفصل الإطار المشترك عن المحتوى المتغيّر."},{"text":"تشترط React أن يُغلَّف كل عنصر في قائمة بـ component.","why":"العناصر العادية تعمل جيدًا في القوائم. الاستخراج خيار من أجل إعادة الاستخدام والوضوح."},{"text":"يتيح للحالة الفارغة أن تتشارك الـ state مع عناصر الأفلام.","why":"الـ components لا تتشارك الـ state أبدًا لمجرّد استخدامها الغلاف نفسه؛ كل نسخة مستقلة."}],"answer":1}],"glossary":[{"id":"vite","term":"Vite","definition":"أداة بناء وخادم تطوير لمشاريع الواجهات الأمامية. يقدّم ملفات المصدر مع تحديثات فورية أثناء التطوير، ويجمّعها في ملفات ثابتة محسّنة داخل dist/ للإنتاج.","lesson":"l-rf-1-2"},{"id":"strict-mode","term":"StrictMode","definition":"component غلاف في React يضيف فحوصًا خاصة بالتطوير، مثل رسم الـ components مرتين وتشغيل الـ effects مرتين، ليكشف الكود غير النقي ودوال التنظيف المفقودة. لا تأثير له في الإنتاج.","lesson":"l-rf-1-2"},{"id":"component","term":"المكوّن (component)","definition":"دالة JavaScript يبدأ اسمها بحرف كبير وتُرجع JSX. تستخدمها كوسم، وتستدعيها React لتعرف ما الذي يجب عرضه.","lesson":"l-rf-1-3"},{"id":"fragment","term":"Fragment","definition":"غلاف يُكتب بالشكل &lt;&gt;…&lt;/&gt; أو <Fragment> يجمع عدّة عناصر من دون إضافة عقدة إلى الـ DOM، فيستطيع الـ component إرجاع عناصر متجاورة كجذر واحد.","lesson":"l-rf-1-3"},{"id":"jsx","term":"JSX","definition":"امتداد لصياغة JavaScript يتيح لك كتابة markup شبيه بـ HTML داخل JavaScript. يحوّل المترجم كل وسم إلى استدعاء دالة يُنشئ عنصر React.","lesson":"l-rf-1-4"},{"id":"react-element","term":"عنصر React (React element)","definition":"كائن JavaScript عادي ينشئه JSX ويصف ما يجب أن يظهر على الشاشة: نوعًا مثل “h2” أو component، إضافةً إلى الـ props الخاصة به. وتحوّل React هذه العناصر إلى DOM.","lesson":"l-rf-1-4"},{"id":"derived-value","term":"القيمة المشتقّة (derived value)","definition":"بيانات تُحسب أثناء الـ render من الـ props أو الـ state، مثل عدد أو قائمة مصفّاة. لا تُخزَّن أبدًا في الـ state، فلا يمكن أن تخرج عن التزامن مع مصدرها.","lesson":"l-rf-2-1"},{"id":"props","term":"Props","definition":"المدخلات التي يمرّرها الأب إلى component كخصائص، وتصل إليه ككائن واحد. الـ props للقراءة فقط: لا يغيّرها الـ component أبدًا، بل يستقبل props جديدة حين يعيد الأب الـ render.","lesson":"l-rf-2-2"},{"id":"children-prop","term":"children","definition":"الـ prop الذي يحمل كل ما يوضع بين وسمي الفتح والإغلاق لـ component. عرض {children} يتيح للـ component أن يغلّف محتوى لا يعرف عنه شيئًا.","lesson":"l-rf-2-3"},{"id":"slot","term":"Slot prop","definition":"prop يقبل JSX، مثل actions={<button>Shuffle</button>}، فيقرّر المستدعي ما الذي يظهر، ويقرّر الـ component أين يظهر.","lesson":"l-rf-2-3"},{"id":"prop-drilling","term":"Prop drilling","definition":"تمرير prop عبر عدّة components لا تستخدمه، فقط لإيصاله إلى component متداخل في العمق. وكثيرًا ما يزيله التركيب بالعناصر أو الـ context.","lesson":"l-rf-2-3"},{"id":"conditional-rendering","term":"العرض الشرطي (conditional rendering)","definition":"اختيار ما يُخرجه الـ component بحسب البيانات، باستخدام return مبكر أو المعامل الثلاثي أو &amp;&amp; داخل JSX. وإرجاع null لا يعرض شيئًا.","lesson":"l-rf-2-4"},{"id":"unmount","term":"إلغاء التركيب (unmount)","definition":"حين تزيل React الـ component من الشجرة، فتهدم الـ DOM والـ state الخاصين به. والـ component المعروض شرطيًا يُلغى تركيبه حين يصبح شرطه false.","lesson":"l-rf-2-4"},{"id":"key","term":"المفتاح (key)","definition":"prop خاص على عناصر القوائم يُخبر React بهوية كل عنصر بين مرّات الـ render. يجب أن يكون فريدًا بين الإخوة وثابتًا، وهو عادةً معرّف من البيانات.","lesson":"l-rf-2-5"},{"id":"state","term":"State","definition":"بيانات يتذكّرها الـ component بين مرّات الـ render، ويُعلَن عنها باستخدام useState. استدعاء الـ setter الخاص بها يخزّن قيمة جديدة ويجعل React تعيد رسم الـ component.","lesson":"l-rf-3-1"},{"id":"hook","term":"Hook","definition":"دالة يبدأ اسمها بـ “use”، مثل useState أو useEffect، تتيح للـ component استخدام ميزات React. ويجب استدعاء الـ hooks في المستوى الأعلى من الـ component.","lesson":"l-rf-3-1"},{"id":"state-snapshot","term":"لقطة الـ state (state snapshot)","definition":"مجموعة قيم الـ state الثابتة التي يراها render واحد. ضبط الـ state لا يغيّر المتغيّرات الحالية، بل يجدول render جديدًا بقيم جديدة.","lesson":"l-rf-3-1"},{"id":"updater-function","term":"دالة التحديث (updater function)","definition":"دالة تُمرَّر إلى setter الـ state، مثل setCount(© =&gt; c + 1). تستدعيها React بأحدث قيمة منتظرة، فتتراكم التحديثات المتتالية بشكل صحيح.","lesson":"l-rf-3-1"},{"id":"immutable-update","term":"التحديث بلا تعديل مباشر (immutable update)","definition":"تغيير الـ state بإنشاء مصفوفات أو كائنات جديدة (باستخدام spread أو map أو filter) بدل تعديل الموجودة، حتى تستطيع React اكتشاف التغيير.","lesson":"l-rf-3-1"},{"id":"event-handler","term":"معالج الحدث (event handler)","definition":"دالة تُمرَّر إلى prop مثل onClick أو onSubmit، تستدعيها React حين يقع الحدث. والمعالجات هي مكان الآثار الجانبية الناتجة عن إجراءات المستخدم.","lesson":"l-rf-3-2"},{"id":"event-bubbling","term":"انتشار الحدث (event bubbling)","definition":"الطريقة التي ينتقل بها الحدث من العنصر الذي وقع عليه صعودًا عبر أسلافه، فيُطلق معالجاتهم أيضًا. والدالة e.stopPropagation() توقفه.","lesson":"l-rf-3-2"},{"id":"controlled-input","term":"الحقل المتحكَّم به (controlled input)","definition":"حقل نموذج تأتي قيمته من الـ state في React، ويحدّث معالج onChange الخاص به ذلك الـ state، فيكون الـ state المصدر الوحيد للحقيقة لما يعرضه الحقل.","lesson":"l-rf-3-3"},{"id":"form-action","term":"Form action","definition":"ميزة في React 19 تستقبل فيها دالة ممرَّرة إلى الخاصية action في النموذج كائن FormData المُرسَل. وتمنع React إعادة تحميل الصفحة وتعيد ضبط الحقول غير المتحكَّم بها بعد ذلك.","lesson":"l-rf-3-3"},{"id":"use-action-state","term":"useActionState","definition":"hook في React 19 يغلّف دالة action ويُرجع آخر نتيجة أنتجتها، ودالة إرسال تمرّرها إلى النموذج، ومؤشّر isPending.","lesson":"l-rf-3-3"},{"id":"lifting-state-up","term":"رفع الـ state للأعلى (lifting state up)","definition":"نقل الـ state من component إلى أقرب أب مشترك لكل الـ components التي تحتاجه، ثم تمرير القيمة ومعالجات التغيير إلى الأسفل كـ props.","lesson":"l-rf-3-4"},{"id":"effect","term":"Effect","definition":"كود يُمرَّر إلى useEffect ويعمل بعد أن تحدّث React الشاشة، ويُستخدم للتزامن مع شيء خارج React، مثل عنوان المستند أو التخزين أو المؤقّتات أو الاشتراكات.","lesson":"l-rf-3-5"},{"id":"dependency-array","term":"مصفوفة الاعتماديات (dependency array)","definition":"الوسيط الثاني لـ useEffect، ويسرد كل قيمة يقرؤها الـ effect. ولا تعيد React تشغيل الـ effect إلا حين تتغيّر إحدى هذه القيم منذ الـ render السابق.","lesson":"l-rf-3-5"},{"id":"cleanup-function","term":"دالة التنظيف (cleanup function)","definition":"دالة يُرجعها الـ effect لتلغي ما فعله، مثل إزالة مستمع أو إيقاف مؤقّت. وتشغّلها React قبل أن يعمل الـ effect مجددًا وعند إلغاء التركيب.","lesson":"l-rf-3-5"},{"id":"utility-class","term":"Utility class","definition":"class صغير في CSS يفعل شيئًا واحدًا، مثل p-4 للحشو أو text-slate-600 للون. ويولّد Tailwind CSS الـ utilities التي تستخدمها ملفاتك.","lesson":"l-rf-4-2"},{"id":"preview-deployment","term":"نسخة المعاينة (preview deployment)","definition":"deployment لـ branch غير الإنتاج أو لـ pull request على رابط فريد خاص به، حتى يمكن فحص التغييرات قبل دمجها ووصولها إلى موقع الإنتاج.","lesson":"l-rf-4-3"}]}