<?xml version="1.0"?>
<rss version="2.0"><channel><title>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: React</title><link>https://academy.hsoub.com/programming/javascript/react/page/2/?d=2</link><description>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: React</description><language>ar</language><item><title>&#x623;&#x641;&#x643;&#x627;&#x631; &#x62D;&#x648;&#x644; &#x62A;&#x646;&#x633;&#x64A;&#x642; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; React</title><link>https://academy.hsoub.com/programming/javascript/react/%D8%A3%D9%81%D9%83%D8%A7%D8%B1-%D8%AD%D9%88%D9%84-%D8%AA%D9%86%D8%B3%D9%8A%D9%82-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-react-r1168/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_03/604e34514c968_----React.png.cf83b11c1944a0b741e93e945890a230.png" /></p>

<p>
	تعرفنا في <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://academy.hsoub.com/programming/javascript/react/%D8%AA%D8%B5%D9%8A%D9%8A%D8%B1-%D9%85%D8%AC%D9%85%D9%88%D8%B9%D8%A9-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D9%85%D9%81%D9%87%D9%88%D9%85-%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-%D9%81%D9%8A-react-r1094/" rel="">القسم 2</a> على طريقتين لإضافة التنسيقات إلى التطبيق، الطريقة القديمة باستخدام ملف CSS واحد وطريقة <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://academy.hsoub.com/programming/javascript/react/%D8%A5%D8%B6%D8%A7%D9%81%D8%A9-%D8%AA%D9%86%D8%B3%D9%8A%D9%82%D8%A7%D8%AA-%D8%A5%D9%84%D9%89-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-react-r1098/" rel="">التنسيق المباشر في المكان</a>.
</p>

<h2>
	مكتبات جاهزة للاستخدام مع واجهة المستخدم UI
</h2>

<p>
	يمكن استخدام مكتبات جاهزة في إضافة التنسيقات إلى التطبيق. وتعتبر مكتبة الأدوات <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://getbootstrap.com/" rel="external nofollow">Bootstrap</a> التي طورتها Twitter، من أكثر إطارات العمل مع واجهة المستخدم شعبية، والتي ستبقى كذلك ربما. ستجد حاليًا عددًا هائلًا من المكتبات التي تنسق واجهة المستخدم، ولديك خيارات واسعة جدًا لا يمكن حصرها في قائمة. تقدم العديد من إطارات عمل UI لمطوري تطبيقات الويب سمات جاهزة و"مكوّنات" كالأزرار والقوائم والجداول. ولقد وضعنا كلمة مكوّنات بين معترضتين لأننا لا نتكلم هنا عن مكوّنات React. تُستخدم إطارات عمل UI عادةً بإدراج ملفات CSS بالإضافة إلى ملفات JavaScript الخاصة بها ضمن التطبيق. تأتي العديد من إطارت عمل UI بنسخ مخصصة للاستخدام مع React، حيث حُوّلت العديد من مكوناتها إلى مكوّنات React. فهنالك نسخ مختلفة من Bootstap مخصصة للعمل مع React مثل <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="http://reactstrap.github.io/" rel="external nofollow">reactstrap</a> و<a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://react-bootstrap.github.io/" rel="external nofollow">react-bootstrap</a>.
</p>

<p>
	سنطلع تاليًا على إطاري العمل <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://academy.hsoub.com/programming/ruby/bootstrap/" rel="">Bootstrap</a> و<a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://material-ui.com/" rel="external nofollow">MaterialUI</a>. وسنستخدمهما لإضافة نفس التنسيقات إلى التطبيق الذي أنشأناه في فصل (مكتبة React-Router) من هذا القسم.
</p>

<h2>
	استخدام إطار العمل React-Bootstrap
</h2>

<p>
	لنلقي نظرة على Bootstrap مستخدمين الحزمة <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://react-bootstrap.github.io/" rel="external nofollow">react-bootstrap</a>. لنثبت هذه الحزمة إذًا:
</p>

<pre class="ipsCode">
npm install react-bootstrap
</pre>

<p>
	ثم سنضيف رابطًا لتحميل ملف تنسيق CSS الخاص بالإطار Bootstarp ضمن المعرّف <code>&lt;head&gt;</code> في الملف "public/index.html"
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5151_8" style="">
<span class="tag">&lt;head&gt;</span><span class="pln">
  </span><span class="tag">&lt;link</span><span class="pln">
    </span><span class="atn">rel</span><span class="pun">=</span><span class="atv">"stylesheet"</span><span class="pln">
    </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"</span><span class="pln">
    </span><span class="atn">integrity</span><span class="pun">=</span><span class="atv">"sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"</span><span class="pln">
    </span><span class="atn">crossorigin</span><span class="pun">=</span><span class="atv">"anonymous"</span><span class="pln">
  </span><span class="tag">/&gt;</span><span class="pln">
  // ...
</span><span class="tag">&lt;/head&gt;</span></pre>

<p>
	سنلاحظ أنّ مظهر التطبيق قد أصبح أفضل عند إعادة تحميله:
</p>

<p style="text-align: center;">
	<img alt="stylish_app_01.png" class="ipsImage ipsImage_thumbnailed" data-fileid="59655" data-unique="4ustwhsh4" src="https://academy.hsoub.com/uploads/monthly_2021_03/stylish_app_01.png.40fa5bdbbbd338870b4064ecf6fb8172.png"></p>

<p>
	تصيّر جميع محتويات التطبيق عند استخدام Bootstrap داخل <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://getbootstrap.com/docs/4.1/layout/overview/#containers" rel="external nofollow">حاوية</a>. ويتم ذلك عمليًا بإعطاء الصفة <code>classname</code> للعنصر &lt;div&gt; الجذري القيمة "container".
</p>

<div>
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5151_10" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div className</span><span class="pun">=</span><span class="str">"container"</span><span class="pun">&gt;</span><span class="pln">      
    	</span><span class="com">// ...</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

	<p>
		وسنجد تأثير ذلك واضحًا على مظهر التطبيق، فلم يعد المحتوى ملاصقًا لحافة المتصفح كما كانت من قبل:
	</p>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" data-fileid="59642" data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/bootstrap_style_container_02.png.98829e44f69c67bfff9ebe5f8cc6dafd.png" rel=""><img alt="bootstrap_style_container_02.png" class="ipsImage ipsImage_thumbnailed" data-fileid="59642" data-unique="xg8afu9c1" src="https://academy.hsoub.com/uploads/monthly_2021_03/bootstrap_style_container_02.png.98829e44f69c67bfff9ebe5f8cc6dafd.png"></a>
	</p>

	<p>
		لنجري بعض التعديلات على المكوّن <code>Notes</code>، بحيث يصيّر قائمة الملاحظات على شكل <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://getbootstrap.com/docs/4.1/content/tables/" rel="external nofollow">جدول</a>. حيث تؤمن React-Bootstrap مكوّن الجدول جاهزًا للاستخدام، فلا حاجة لتعريف أية أصناف CSS مفصلة.
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5151_12" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Notes</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="typ">Notes</span><span class="pun">&lt;/</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">Table</span><span class="pln"> striped</span><span class="pun">&gt;</span><span class="pln">      
    </span><span class="pun">&lt;</span><span class="pln">tbody</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="pln">tr key</span><span class="pun">={</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="pln">td</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="pun">&lt;</span><span class="typ">Link</span><span class="pln"> to</span><span class="pun">={`/</span><span class="pln">notes</span><span class="pun">/</span><span class="pln">$</span><span class="pun">{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}`}&gt;</span><span class="pln">
                </span><span class="pun">{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">content</span><span class="pun">}</span><span class="pln">
              </span><span class="pun">&lt;/</span><span class="typ">Link</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;/</span><span class="pln">td</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="pln">td</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="pun">{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">user</span><span class="pun">}</span><span class="pln">
            </span><span class="pun">&lt;/</span><span class="pln">td</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;/</span><span class="pln">tr</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">)}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">tbody</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="typ">Table</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">)</span></pre>

	<p>
		لقد أصبح تنسيق التطبيق أفضل:
	</p>

	<p style="text-align: center;">
		<img alt="table_style_03.png" class="ipsImage ipsImage_thumbnailed" data-fileid="59656" data-unique="awoltgk31" src="https://academy.hsoub.com/uploads/monthly_2021_03/table_style_03.png.5ccbe9717e53c1166bd7676750a793ac.png"></p>

	<p>
		لاحظ أنّه عليك إدراج مكونات React-Bootstrap بشكل منفصل من المكتبة كالتالي:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5151_14" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Table</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react-bootstrap'</span></pre>

	<h3>
		النماذج
	</h3>

	<p>
		لنحسّن نموذج تسجيل الدخول بمساعدة <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://getbootstrap.com/docs/4.1/components/forms/" rel="external nofollow">نماذج </a>Bootstrap.
	</p>

	<p>
		تأتي المكتبة React-Bootstrap <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://react-bootstrap.github.io/components/forms/" rel="external nofollow">بمكوّنات</a> مدمجة لإنشاء النماذج (على الرغم من النقص الواضح في توثيق هذا الموضوع):
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5151_16" style="">
<span class="pln">let </span><span class="typ">Login</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">login</span><span class="pun">&lt;/</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Form</span><span class="pln"> onSubmit</span><span class="pun">={</span><span class="pln">onSubmit</span><span class="pun">}&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">Form</span><span class="pun">.</span><span class="typ">Group</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Form</span><span class="pun">.</span><span class="typ">Label</span><span class="pun">&gt;</span><span class="pln">username</span><span class="pun">:&lt;/</span><span class="typ">Form</span><span class="pun">.</span><span class="typ">Label</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Form</span><span class="pun">.</span><span class="typ">Control</span><span class="pln">
            type</span><span class="pun">=</span><span class="str">"text"</span><span class="pln">
            name</span><span class="pun">=</span><span class="str">"username"</span><span class="pln">
          </span><span class="pun">/&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Form</span><span class="pun">.</span><span class="typ">Label</span><span class="pun">&gt;</span><span class="pln">password</span><span class="pun">:&lt;/</span><span class="typ">Form</span><span class="pun">.</span><span class="typ">Label</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Form</span><span class="pun">.</span><span class="typ">Control</span><span class="pln">
            type</span><span class="pun">=</span><span class="str">"password"</span><span class="pln">
          </span><span class="pun">/&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Button</span><span class="pln"> variant</span><span class="pun">=</span><span class="str">"primary"</span><span class="pln"> type</span><span class="pun">=</span><span class="str">"submit"</span><span class="pun">&gt;</span><span class="pln">
            login
          </span><span class="pun">&lt;/</span><span class="typ">Button</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="typ">Form</span><span class="pun">.</span><span class="typ">Group</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="typ">Form</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">)}</span></pre>

	<p>
		سيزداد عدد المكونات التي سندرجها شيئًا فشيئًا:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5151_18" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Table</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Form</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Button</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react-bootstrap'</span></pre>

	<p>
		سيبدو التطبيق بعد التحوّل إلى نموذج Bootstrap كالتالي:
	</p>

	<p style="text-align: center;">
		<img alt="notification_style_04.png" class="ipsImage ipsImage_thumbnailed" data-fileid="59653" data-unique="ya4dhfrco" src="https://academy.hsoub.com/uploads/monthly_2021_03/notification_style_04.png.5fe727aafaf7ab4e717424c0c4fe1c59.png"></p>

	<h3>
		التنبيهات
	</h3>

	<p>
		سنحسّن التنبيهات أيضًا في تطبيقنا بعد أن حسنّا مظهر النماذج.:
	</p>

	<p style="text-align: center;">
		<img alt="navbar_style_05.png" class="ipsImage ipsImage_thumbnailed" data-fileid="59651" data-unique="ysyewqkfm" src="https://academy.hsoub.com/uploads/monthly_2021_03/navbar_style_05.png.db6f54bce0b270f18773e94b4665258c.png"></p>

	<p>
		لنضف رسالة إلى التنبيهات عندما يسجل المستخدم دخوله إلى التطبيق، وسنخزّنها ضمن المتغير <code>message</code> في حالة المكوّن <code>App</code>:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5151_20" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">notes</span><span class="pun">,</span><span class="pln"> setNotes</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">([</span><span class="pln">
    </span><span class="com">// ...</span><span class="pln">
  </span><span class="pun">])</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">user</span><span class="pun">,</span><span class="pln"> setUser</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="kwd">null</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">message</span><span class="pun">,</span><span class="pln"> setMessage</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="kwd">null</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> login </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">user</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    setUser</span><span class="pun">(</span><span class="pln">user</span><span class="pun">)</span><span class="pln">
    setMessage</span><span class="pun">(`</span><span class="pln">welcome $</span><span class="pun">{</span><span class="pln">user</span><span class="pun">}`)</span><span class="pln">    
      setTimeout</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">      
          setMessage</span><span class="pun">(</span><span class="kwd">null</span><span class="pun">)</span><span class="pln">    
      </span><span class="pun">},</span><span class="pln"> </span><span class="lit">10000</span><span class="pun">)</span><span class="pln">  
  </span><span class="pun">}</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

	<p>
		سنصيّر الرسالة على أنها مكون <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://getbootstrap.com/docs/4.1/components/alerts/" rel="external nofollow">تنبيه</a> Bootstrap. ولاحظ مجددًا أنّ المكتبة React-Bootstrap ستزودنا بالمكون المقابل <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://react-bootstrap.github.io/components/alerts/" rel="external nofollow">لمكون Recat</a>.
	</p>

	<h3>
		أدوات التنقل
	</h3>

	<p>
		لنغيّر أخيرًا قائمة التنقل في التطبيق مستخدمين المكوّن <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://getbootstrap.com/docs/4.1/components/navbar/" rel="external nofollow">Navbar</a> من Bootstrap. تزوّدنا المكتبة Bootstrap <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://react-bootstrap.github.io/components/navbar/#navbars-mobile-friendly" rel="external nofollow">بمكونات مدمجة</a> مقابلة. لقد وجدنا من خلال المحاولة والخطأ حلًا مرضيًا، على الرغم من التوثيق غير الواضح:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5151_22" style="">
<span class="tag">&lt;Navbar</span><span class="pln"> </span><span class="atn">collapseOnSelect</span><span class="pln"> </span><span class="atn">expand</span><span class="pun">=</span><span class="atv">"lg"</span><span class="pln"> </span><span class="atn">bg</span><span class="pun">=</span><span class="atv">"dark"</span><span class="pln"> </span><span class="atn">variant</span><span class="pun">=</span><span class="atv">"dark"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;Navbar.Toggle</span><span class="pln"> </span><span class="atn">aria-controls</span><span class="pun">=</span><span class="atv">"responsive-navbar-nav"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
  </span><span class="tag">&lt;Navbar.Collapse</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"responsive-navbar-nav"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;Nav</span><span class="pln"> </span><span class="atn">className</span><span class="pun">=</span><span class="atv">"mr-auto"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;Nav.Link</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"#"</span><span class="pln"> </span><span class="atn">as</span><span class="pun">=</span><span class="atv">"span"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;Link</span><span class="pln"> </span><span class="atn">style</span><span class="pun">={</span><span class="pln">padding</span><span class="pun">}</span><span class="pln"> </span><span class="atn">to</span><span class="pun">=</span><span class="atv">"/"</span><span class="tag">&gt;</span><span class="pln">home</span><span class="tag">&lt;/Link&gt;</span><span class="pln">
      </span><span class="tag">&lt;/Nav.Link&gt;</span><span class="pln">
      </span><span class="tag">&lt;Nav.Link</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"#"</span><span class="pln"> </span><span class="atn">as</span><span class="pun">=</span><span class="atv">"span"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;Link</span><span class="pln"> </span><span class="atn">style</span><span class="pun">={</span><span class="pln">padding</span><span class="pun">}</span><span class="pln"> </span><span class="atn">to</span><span class="pun">=</span><span class="atv">"/notes"</span><span class="tag">&gt;</span><span class="pln">notes</span><span class="tag">&lt;/Link&gt;</span><span class="pln">
      </span><span class="tag">&lt;/Nav.Link&gt;</span><span class="pln">
      </span><span class="tag">&lt;Nav.Link</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"#"</span><span class="pln"> </span><span class="atn">as</span><span class="pun">=</span><span class="atv">"span"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;Link</span><span class="pln"> </span><span class="atn">style</span><span class="pun">={</span><span class="pln">padding</span><span class="pun">}</span><span class="pln"> </span><span class="atn">to</span><span class="pun">=</span><span class="atv">"/users"</span><span class="tag">&gt;</span><span class="pln">users</span><span class="tag">&lt;/Link&gt;</span><span class="pln">
      </span><span class="tag">&lt;/Nav.Link&gt;</span><span class="pln">
      </span><span class="tag">&lt;Nav.Link</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"#"</span><span class="pln"> </span><span class="atn">as</span><span class="pun">=</span><span class="atv">"span"</span><span class="tag">&gt;</span><span class="pln">
        {user
          ? </span><span class="tag">&lt;em&gt;</span><span class="pln">{user} logged in</span><span class="tag">&lt;/em&gt;</span><span class="pln">
          : </span><span class="tag">&lt;Link</span><span class="pln"> </span><span class="atn">to</span><span class="pun">=</span><span class="atv">"/login"</span><span class="tag">&gt;</span><span class="pln">login</span><span class="tag">&lt;/Link&gt;</span><span class="pln">
        }
    </span><span class="tag">&lt;/Nav.Link&gt;</span><span class="pln">
    </span><span class="tag">&lt;/Nav&gt;</span><span class="pln">
  </span><span class="tag">&lt;/Navbar.Collapse&gt;</span><span class="pln">
</span><span class="tag">&lt;/Navbar&gt;</span></pre>

	<p>
		لشريط التنقل الناتج مظهرًا واضحًا ومريحًا:
	</p>

	<p style="text-align: center;">
		<img alt="navbar_viewport_change_06.png" class="ipsImage ipsImage_thumbnailed" data-fileid="59652" data-unique="ha1zhsyu5" src="https://academy.hsoub.com/uploads/monthly_2021_03/navbar_viewport_change_06.png.a4ed65866a788e4a6b85a50afb406692.png"></p>

	<p>
		إن تغيّر حجم شاشة العرض على المتصفح، سنجد أن القائمة ستختفي تحت زر "الهامبرغر" وستظهر مجددًا بالنقر عليه:
	</p>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" data-fileid="59643" data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/chrome_view_simulation_07.png.3631654f53e680419d04ceb414891d0a.png" rel=""><img alt="chrome_view_simulation_07.png" class="ipsImage ipsImage_thumbnailed" data-fileid="59643" data-unique="rsssn32zf" src="https://academy.hsoub.com/uploads/monthly_2021_03/chrome_view_simulation_07.png.3631654f53e680419d04ceb414891d0a.png"></a>
	</p>

	<p>
		تقدم Bootstrap والعديد من أطر عمل UI تصاميم <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://academy.hsoub.com/programming/css/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D9%85%D8%AA%D8%AC%D8%A7%D9%88%D8%A8-%D8%A7%D9%84%D8%B9%D9%86%D8%A7%D8%B5%D8%B1-%D8%A7%D9%84%D8%B2%D8%A7%D8%A6%D9%81%D8%A9-%D9%88%D8%A7%D8%B3%D8%AA%D8%B9%D9%84%D8%A7%D9%85%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D8%B3%D8%A7%D8%A6%D8%B7-%D9%88%D8%BA%D9%8A%D8%B1%D9%87%D8%A7-r787/" rel="">متجاوبة</a> بحيث تُصيّر التطبيقات بشكل يناسب القياسات المختلفة لشاشات العرض.
	</p>

	<p>
		ستساعدك أدوات تطوير Chrome على محاكاة استخدام التطبيق ضمن متصفحات أنواع مختلفة من الهواتف النقالة:
	</p>

	<p style="text-align: center;">
		<img alt="chrome_view_simulation_08.png" class="ipsImage ipsImage_thumbnailed" data-fileid="59644" data-unique="abw11o1ov" src="https://academy.hsoub.com/uploads/monthly_2021_03/chrome_view_simulation_08.png.5ba0df9cb3ace1f8d3a92651c0d33071.png"></p>

	<p>
		يمكنك أن تجد الشيفرة كاملة على <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://github.com/fullstack-hy2020/misc/blob/master/notes-bootstrap.js" rel="external nofollow">GitHub</a>.
	</p>

	<h2>
		إطار العمل Material UI
	</h2>

	<p>
		سنلقي نظرة الآن على المكتبة <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://material-ui.com/" rel="external nofollow">MaterialUI</a> التي تعمل مع React، والتي تستخدم اللغة المرئية <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://material.io/" rel="external nofollow">لتصميم المواد</a> والمطوّرة من قبل Google. لنثبت هذه المكتبة:
	</p>

	<pre class="ipsCode">
npm install @material-ui/core
</pre>

	<p>
		ثم سنضيف السطر التالي إلى المعرّف
	</p>
</div>

<p>
	في الملف "public/index.html"، حيث يحمًل هذا السطر الخط "Roboto" من تصميم Google:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5151_24" style="">
<span class="tag">&lt;head&gt;</span><span class="pln">
  </span><span class="tag">&lt;link</span><span class="pln"> </span><span class="atn">rel</span><span class="pun">=</span><span class="atv">"stylesheet"</span><span class="pln"> </span><span class="atn">href</span><span class="pun">=</span><span class="atv">"https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&amp;display=swap"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
  // ...
</span><span class="tag">&lt;/head&gt;</span></pre>

<p>
	سنستخدم الآن MaterialUI لتنفيذ نفس التغييرات التي أجريناها سابقًا باستخدام Bootstrap.
</p>

<p>
	سنصيّر التطبيق كاملًا ضمن <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://material-ui.com/components/container/" rel="external nofollow">حاوية</a>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5151_26" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">Container</span><span class="pln"> from </span><span class="str">'@material-ui/core/Container'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">Container</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="com">// ...</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="typ">Container</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لنبدأ بالمكوّن <code>Note</code> ونصيّر قائمة الملاحظات ضمن <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://material-ui.com/components/tables/#simple-table" rel="external nofollow">جدول</a>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5151_28" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Notes</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln">notes</span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="typ">Notes</span><span class="pun">&lt;/</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">

    </span><span class="pun">&lt;</span><span class="typ">TableContainer</span><span class="pln"> component</span><span class="pun">={</span><span class="typ">Paper</span><span class="pun">}&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Table</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">TableBody</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">{</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="typ">TableRow</span><span class="pln"> key</span><span class="pun">={</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}&gt;</span><span class="pln">
              </span><span class="pun">&lt;</span><span class="typ">TableCell</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">&lt;</span><span class="typ">Link</span><span class="pln"> to</span><span class="pun">={`/</span><span class="pln">notes</span><span class="pun">/</span><span class="pln">$</span><span class="pun">{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}`}&gt;{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">content</span><span class="pun">}&lt;/</span><span class="typ">Link</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="pun">&lt;/</span><span class="typ">TableCell</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="pun">&lt;</span><span class="typ">TableCell</span><span class="pun">&gt;</span><span class="pln">
                </span><span class="pun">{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">name</span><span class="pun">}</span><span class="pln">
              </span><span class="pun">&lt;/</span><span class="typ">TableCell</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;/</span><span class="typ">TableRow</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">))}</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="typ">TableBody</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="typ">Table</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="typ">TableContainer</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">)</span></pre>

<p>
	ستبدو النتيجة كالتالي:
</p>

<p style="text-align: center;">
	<img alt="materialui_table_09.png" class="ipsImage ipsImage_thumbnailed" data-fileid="59650" data-unique="8cok7sl0f" src="https://academy.hsoub.com/uploads/monthly_2021_03/materialui_table_09.png.ea4def584a402ef36722fd5c332cacdd.png"></p>

<p>
	إنّ إدراج كل مكون بشكل منفصل، هي إحدى المزايا غير المرضية في MaterialUI. إذ تكون قائمة المكوّنات التي سندرجها طويلة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5151_30" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="typ">Container</span><span class="pun">,</span><span class="pln">
  </span><span class="typ">Table</span><span class="pun">,</span><span class="pln">
  </span><span class="typ">TableBody</span><span class="pun">,</span><span class="pln">
  </span><span class="typ">TableCell</span><span class="pun">,</span><span class="pln">
  </span><span class="typ">TableContainer</span><span class="pun">,</span><span class="pln">
  </span><span class="typ">TableRow</span><span class="pun">,</span><span class="pln">
  </span><span class="typ">Paper</span><span class="pun">,</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> from </span><span class="str">'@material-ui/core'</span></pre>

<h3>
	النماذج
</h3>

<p>
	سنحسّن مظهر نموذج تسجيل الدخول باستخدام المكوّنين <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://material-ui.com/components/text-fields/" rel="external nofollow">TextField</a> و<a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://material-ui.com/api/button/" rel="external nofollow">Button</a>
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5151_32" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Login</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> history </span><span class="pun">=</span><span class="pln"> useHistory</span><span class="pun">()</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> onSubmit </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">
    props</span><span class="pun">.</span><span class="pln">onLogin</span><span class="pun">(</span><span class="str">'mluukkai'</span><span class="pun">)</span><span class="pln">
    history</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="str">'/'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">login</span><span class="pun">&lt;/</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">form onSubmit</span><span class="pun">={</span><span class="pln">onSubmit</span><span class="pun">}&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">TextField</span><span class="pln"> label</span><span class="pun">=</span><span class="str">"username"</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">TextField</span><span class="pln">  label</span><span class="pun">=</span><span class="str">"password"</span><span class="pln"> type</span><span class="pun">=</span><span class="str">'password'</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Button</span><span class="pln"> variant</span><span class="pun">=</span><span class="str">"contained"</span><span class="pln"> color</span><span class="pun">=</span><span class="str">"primary"</span><span class="pln"> type</span><span class="pun">=</span><span class="str">"submit"</span><span class="pun">&gt;</span><span class="pln">
            login
          </span><span class="pun">&lt;/</span><span class="typ">Button</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وستكون النتيجة كالتالي:
</p>

<p style="text-align: center;">
	<img alt="materialui_form_10.png" class="ipsImage ipsImage_thumbnailed" data-fileid="59647" data-unique="xtsxdz0g2" src="https://academy.hsoub.com/uploads/monthly_2021_03/materialui_form_10.png.ca6b9289922e846df61427a024d3fcae.png"></p>

<p>
	لا تؤمن MaterialUi مكون خاص بالنماذج كما في Bootstrap. فالنموذج هنا هو <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://wiki.hsoub.com/HTML/form" rel="external">نموذج</a> HTML نظامي. وتذكر أن تدرج كل المكوّنات الموجودة في النموذج.
</p>

<h3>
	التنبيهات
</h3>

<p>
	يمكن عرض التنبيهات باستخدام المكون <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://material-ui.com/components/alert/" rel="external nofollow">Alert</a> والذي يشابه تمامًا المكون المقابل في Bootstarp:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5151_34" style="">
<span class="tag">&lt;div&gt;</span><span class="pln">
  {(message &amp;&amp;    
   </span><span class="tag">&lt;Alert</span><span class="pln"> </span><span class="atn">severity</span><span class="pun">=</span><span class="atv">"success"</span><span class="tag">&gt;</span><span class="pln">      
   {message}    
</span><span class="tag">&lt;/Alert&gt;</span><span class="pln">  
)}
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	لا تتضمن الحزمة الأساسية للإطار MaterialUI المكوّن Alert بعد، لذلك لا بد من تثبيت الحزمة <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://material-ui.com/components/about-the-lab/" rel="external nofollow">lab</a> لاستخدامه:
</p>

<pre class="ipsCode">
npm install @material-ui/lab
</pre>

<p>
	وبعدها يمكننا إدراج المكوّن كالتالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5151_36" style="">
<span class="pln">import { Alert } from '@material-ui/lab'</span></pre>

<p>
	سيبدو التنبيه أنيق المظهر:
</p>

<p style="text-align: center;">
	<img alt="materialui_alert_11.png" class="ipsImage ipsImage_thumbnailed" data-fileid="59646" data-unique="itfzf01l3" src="https://academy.hsoub.com/uploads/monthly_2021_03/materialui_alert_11.png.697a649723df2f5b121e8d8aa060378b.png"></p>

<h2>
	أدوات التنقل
</h2>

<p>
	يمكننا إدراج أدوات التنقل باستخدام المكوّن <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://material-ui.com/components/app-bar/" rel="external nofollow">AppBar</a> . فلو استعملنا المثال الوارد في التوثيق:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5151_38" style="">
<span class="tag">&lt;AppBar</span><span class="pln"> </span><span class="atn">position</span><span class="pun">=</span><span class="atv">"static"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;Toolbar&gt;</span><span class="pln">
    </span><span class="tag">&lt;IconButton</span><span class="pln"> </span><span class="atn">edge</span><span class="pun">=</span><span class="atv">"start"</span><span class="pln"> </span><span class="atn">color</span><span class="pun">=</span><span class="atv">"inherit"</span><span class="pln"> </span><span class="atn">aria-label</span><span class="pun">=</span><span class="atv">"menu"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;/IconButton&gt;</span><span class="pln">
    </span><span class="tag">&lt;Button</span><span class="pln"> </span><span class="atn">color</span><span class="pun">=</span><span class="atv">"inherit"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;Link</span><span class="pln"> </span><span class="atn">to</span><span class="pun">=</span><span class="atv">"/"</span><span class="tag">&gt;</span><span class="pln">home</span><span class="tag">&lt;/Link&gt;</span><span class="pln">
    </span><span class="tag">&lt;/Button&gt;</span><span class="pln">
    </span><span class="tag">&lt;Button</span><span class="pln"> </span><span class="atn">color</span><span class="pun">=</span><span class="atv">"inherit"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;Link</span><span class="pln"> </span><span class="atn">to</span><span class="pun">=</span><span class="atv">"/notes"</span><span class="tag">&gt;</span><span class="pln">notes</span><span class="tag">&lt;/Link&gt;</span><span class="pln">
    </span><span class="tag">&lt;/Button&gt;</span><span class="pln">
    </span><span class="tag">&lt;Button</span><span class="pln"> </span><span class="atn">color</span><span class="pun">=</span><span class="atv">"inherit"</span><span class="tag">&gt;</span><span class="pln">
      </span><span class="tag">&lt;Link</span><span class="pln"> </span><span class="atn">to</span><span class="pun">=</span><span class="atv">"/users"</span><span class="tag">&gt;</span><span class="pln">users</span><span class="tag">&lt;/Link&gt;</span><span class="pln">
    </span><span class="tag">&lt;/Button&gt;</span><span class="pln">  
    </span><span class="tag">&lt;Button</span><span class="pln"> </span><span class="atn">color</span><span class="pun">=</span><span class="atv">"inherit"</span><span class="tag">&gt;</span><span class="pln">
      {user
        ? </span><span class="tag">&lt;em&gt;</span><span class="pln">{user} logged in</span><span class="tag">&lt;/em&gt;</span><span class="pln">
        : </span><span class="tag">&lt;Link</span><span class="pln"> </span><span class="atn">to</span><span class="pun">=</span><span class="atv">"/login"</span><span class="tag">&gt;</span><span class="pln">login</span><span class="tag">&lt;/Link&gt;</span><span class="pln">
      }
    </span><span class="tag">&lt;/Button&gt;</span><span class="pln">                
  </span><span class="tag">&lt;/Toolbar&gt;</span><span class="pln">
</span><span class="tag">&lt;/AppBar&gt;</span></pre>

<p>
	سيفي ذلك بالغرض، لكن يمكن أن نحسن شريط التنقل أكثر:
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="59649" data-unique="q3k93356s" src="https://academy.hsoub.com/uploads/monthly_2021_03/materialui_navbar_basic_12.png.04983e9215a85f7f6b989756f2930c58.png" alt="materialui_navbar_basic_12.png"></p>

<p>
	حيث ستجد طرقًا أفضل ضمن <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://material-ui.com/guides/composition/#routing-libraries" rel="external nofollow">التوثيق</a>. إذ يمكن استخدام <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://material-ui.com/guides/composition/#component-prop" rel="external nofollow">خصائص المكوّن</a> لتحديد الطريقة التي يُصير بها العنصر الجذري لمكوّن MaterialUI، وذلك كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5151_40" style="">
<span class="tag">&lt;Button</span><span class="pln"> </span><span class="atn">color</span><span class="pun">=</span><span class="atv">"inherit"</span><span class="pln"> </span><span class="atn">component</span><span class="pun">=</span><span class="atv">{Link}</span><span class="pln"> </span><span class="atn">to</span><span class="pun">=</span><span class="atv">"/"</span><span class="tag">&gt;</span><span class="pln">
  home
</span><span class="tag">&lt;/Button&gt;</span></pre>

<p>
	سيُصيّر المكون <code>Botton</code> بجيث يكون مكوّنه الأب (الجذري) هو المكوّن <code>Link</code> من المكتبة react-router-dom ويستقبل مساره من خلال الخاصية <code>to</code>. ستكون شيفرة أدوات التنقل كالتالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5151_42" style="">
<span class="tag">&lt;AppBar</span><span class="pln"> </span><span class="atn">position</span><span class="pun">=</span><span class="atv">"static"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;Toolbar&gt;</span><span class="pln">
    </span><span class="tag">&lt;Button</span><span class="pln"> </span><span class="atn">color</span><span class="pun">=</span><span class="atv">"inherit"</span><span class="pln"> </span><span class="atn">component</span><span class="pun">=</span><span class="atv">{Link}</span><span class="pln"> </span><span class="atn">to</span><span class="pun">=</span><span class="atv">"/"</span><span class="tag">&gt;</span><span class="pln">
      home
    </span><span class="tag">&lt;/Button&gt;</span><span class="pln">
    </span><span class="tag">&lt;Button</span><span class="pln"> </span><span class="atn">color</span><span class="pun">=</span><span class="atv">"inherit"</span><span class="pln"> </span><span class="atn">component</span><span class="pun">=</span><span class="atv">{Link}</span><span class="pln"> </span><span class="atn">to</span><span class="pun">=</span><span class="atv">"/notes"</span><span class="tag">&gt;</span><span class="pln">
      notes
    </span><span class="tag">&lt;/Button&gt;</span><span class="pln">
    </span><span class="tag">&lt;Button</span><span class="pln"> </span><span class="atn">color</span><span class="pun">=</span><span class="atv">"inherit"</span><span class="pln"> </span><span class="atn">component</span><span class="pun">=</span><span class="atv">{Link}</span><span class="pln"> </span><span class="atn">to</span><span class="pun">=</span><span class="atv">"/users"</span><span class="tag">&gt;</span><span class="pln">
      users
    </span><span class="tag">&lt;/Button&gt;</span><span class="pln">   
    {user
      ? </span><span class="tag">&lt;em&gt;</span><span class="pln">{user} logged in</span><span class="tag">&lt;/em&gt;</span><span class="pln">
      : </span><span class="tag">&lt;Button</span><span class="pln"> </span><span class="atn">color</span><span class="pun">=</span><span class="atv">"inherit"</span><span class="pln"> </span><span class="atn">component</span><span class="pun">=</span><span class="atv">{Link}</span><span class="pln"> </span><span class="atn">to</span><span class="pun">=</span><span class="atv">"/login"</span><span class="tag">&gt;</span><span class="pln">
          login
        </span><span class="tag">&lt;/Button&gt;</span><span class="pln">
    }                              
  </span><span class="tag">&lt;/Toolbar&gt;</span><span class="pln">
</span><span class="tag">&lt;/AppBar&gt;</span></pre>

<p>
	وستظهر النتيجة كالتالي:
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="59648" data-unique="5dlqjaz85" src="https://academy.hsoub.com/uploads/monthly_2021_03/materialui_navbar_13.png.bcc03d86d6c5241968e4c12c4d2957e4.png" alt="materialui_navbar_13.png"></p>

<p>
	ستجد الشيفرة كاملة على <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://github.com/fullstack-hy2020/misc/blob/master/notes-materialui.js" rel="external nofollow">GitHub</a>.
</p>

<h2>
	أفكار ختامية
</h2>

<p>
	ليس هناك خلاف واسع بين react-bootstrap وMaterialUI. وسيكون الخيار لك. ويشير معد هذا المنهاج إلى أنه استخدم MaterialUi كثيرًا وكانت انطباعاته الأولى إيجابية. فتوثيق المكتبة أفضل قليلًا. وبناء على إحصاءات موقع <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://www.npmtrends.com/" ipsnoembed="true" rel="external nofollow">https://www.npmtrends.com/</a> الذي يتابع شعبية مكتبات npm المختلفة فقد تجاوزت شعبية MaterialUI مكتبةReact-Bootstrap عام 2020: 
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="59645" data-ss1615738511="1" data-ss1615738714="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/maerialUi_vs_react_bootstrap_14.png.403597628a748b299049b973f00249e2.png" rel=""><img alt="maerialUi_vs_react_bootstrap_14.png" class="ipsImage ipsImage_thumbnailed" data-fileid="59645" data-unique="orqrc3sa0" src="https://academy.hsoub.com/uploads/monthly_2021_03/maerialUi_vs_react_bootstrap_14.thumb.png.1d017d624312bf2d7b9a96120a1123f3.png"></a>
</p>

<p>
	لقد استخدمنا في الأمثلة السابقة إطارات عمل UI بالاستعانة بمكتبات React-integration بدلًا من المكتبة <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://react-bootstrap.github.io/" rel="external nofollow">React Bootstrap</a>. وقد كان بمقدورنا استخدامها مباشرةً بتعريف أصناف CSS ضمن عناصر HTML في التطبيق، بدلًا من تعريف الجدول كمكوّن آخر هو <code>Table</code> على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5151_44" style="">
<span class="tag">&lt;Table</span><span class="pln"> </span><span class="atn">striped</span><span class="tag">&gt;</span><span class="pln">
  // ...
</span><span class="tag">&lt;/Table&gt;</span></pre>

<p>
	حيث يمكننا استخدام جدول HTML اعتيادي وتزويده بصنف CSS المطلوب:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5151_46" style="">
<span class="tag">&lt;table</span><span class="pln"> </span><span class="atn">className</span><span class="pun">=</span><span class="atv">"table striped"</span><span class="tag">&gt;</span><span class="pln">
  // ...
</span><span class="tag">&lt;/table&gt;</span></pre>

<p>
	لن تتوضح فكرة استخدام React-Bootstrap من خلال هذا المثال. فبالإضافة إلى جعل شيفرة الواجهة الأمامية أكثر اختصارًا وأكثر قابلية للقراءة، فالفائدة الأخرى لاستخدام مكتبات React UI هي أنها تتضمن شيفرة JavaScript اللازمة لعمل بعض المكونات الخاصة. إذ تتطلب بعض مكونات React <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://getbootstrap.com/docs/4.1/getting-started/introduction/#js" rel="external nofollow">اعتماديات JavaScript</a> والتي نفضل عدم إدراجها في تطبيقات React.
</p>

<p>
	إنّ بعض سلبيات استخدام إطارات عمل UI من خلال مكتبات التكامل بدلًا من استخدامها مباشرةً، هي احتمال وجود واجهات برمجية غير مستقرة ضمن تلك المكتبات أو أنها قد تعاني نقصًا في توثيقها. إلّا أنّ حالة <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://react.semantic-ui.com/" rel="external nofollow">Semantic UI React</a> مثلًا أفضل بكثير من غيرها من إطارت عمل UI، كونها مكتبة تكامل رسمية من مكتبات React.
</p>

<p>
	وهنالك أيضًا تساؤلات حول ضرورة أو عدم ضرورة استخدام إطارت عمل UI أصلًا. وهذا أمر عائد لكل شخص. أما بالنسبة إلى الأشخاص الذين تنقصهم المعرفة بتنسيقات CSS وتصميمات الويب فهي قطعًا أدوات مفيدة.
</p>

<h2>
	أطر عمل UI أخرى
</h2>

<p>
	سنقدم لك قائمة بأكثر عمل UI قد تناسبك. فإن لم تجد الإطار المفضل لديك موجودًا بينها، فقدم طلب إلغاء هذه القائمة من مادة المنهاج.
</p>

<ul>
<li>
		<a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://bulma.io" rel="external nofollow">https://bulma.io</a>
	</li>
	<li>
		<a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://ant.design" rel="external nofollow">https://ant.design</a>
	</li>
	<li>
		<a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://get.foundation" rel="external nofollow">https://get.foundation</a>
	</li>
	<li>
		<a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://chakra-ui.com" rel="external nofollow">https://chakra-ui.com</a>
	</li>
	<li>
		<a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://tailwindcss.com" rel="external nofollow">https://tailwindcss.com</a>
	</li>
</ul>
<h2>
	المكتبة Styled components
</h2>

<p>
	هناك أيضًا <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://blog.bitsrc.io/5-ways-to-style-react-components-in-2019-30f1ccc2b5b" rel="external nofollow">طرق أخرى</a> في تنسيق تطببيقات React لم نأت على ذكرها بعد. منها المكتبة والتي تقدم طريقة مهمة في تنسيق العناصر من خلال <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://wiki.hsoub.com/JavaScript/Template_Literals" rel="external">قوالب موسومة مجردة</a> ظهرت للمرة الأولى مع ES6.
</p>

<p>
	لنجري بعض التغييرات على تنسيق تطبيقنا بمساعدة المكتبة السابقة، لكن علينا أولًا تثبيت الحزمة كالتالي:
</p>

<pre class="ipsCode">
npm install styled-components
</pre>

<p>
	لنعرّف مكوّنين يحملان معلومات تنسيق كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5151_53" style="">
<span class="kwd">import</span><span class="pln"> styled from </span><span class="str">'styled-components'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Button</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> styled</span><span class="pun">.</span><span class="pln">button</span><span class="pun">`</span><span class="pln">
  background</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Bisque</span><span class="pun">;</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1em</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1em</span><span class="pun">;</span><span class="pln">
  padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0.25em</span><span class="pln"> </span><span class="lit">1em</span><span class="pun">;</span><span class="pln">
  border</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2px</span><span class="pln"> solid </span><span class="typ">Chocolate</span><span class="pun">;</span><span class="pln">
  border</span><span class="pun">-</span><span class="pln">radius</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3px</span><span class="pun">;</span><span class="pln">
</span><span class="pun">`</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Input</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> styled</span><span class="pun">.</span><span class="pln">input</span><span class="pun">`</span><span class="pln">
  margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0.25em</span><span class="pun">;</span><span class="pln">
</span><span class="pun">`</span></pre>

<p>
	تنشئ الشيفرة السابقة نسختين تحملا تنسيقًا من عنصرين هما <code>input</code> و<code>button</code>، ومن ثم تسندهما إلى متغيرين يحملان الاسم ذاته.
</p>

<p>
	إنّ الطريقة التي يُعرّف بها التنسيق مميزة، حيث عُرّفت قواعد تنسيق CSS داخل أقواس. وسيعمل المكوّن الذي يحمل تنسيقًا بنفس الطريقة التي يعمل بها الزر أو عنصر الإدخال النظاميين، كما يمكن استخدامهما بالطريقة ذاتها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5151_55" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Login</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">login</span><span class="pun">&lt;/</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">form onSubmit</span><span class="pun">={</span><span class="pln">onSubmit</span><span class="pun">}&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
          username</span><span class="pun">:</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Input</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">        </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
          password</span><span class="pun">:</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Input</span><span class="pln"> type</span><span class="pun">=</span><span class="str">'password'</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">        
              </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">Button</span><span class="pln"> type</span><span class="pun">=</span><span class="str">"submit"</span><span class="pln"> primary</span><span class="pun">=</span><span class="str">''</span><span class="pun">&gt;</span><span class="pln">login</span><span class="pun">&lt;/</span><span class="typ">Button</span><span class="pun">&gt;</span><span class="pln">      
      </span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لننشئ عدة مكونات أخرى لتنسيق هذا التطبيق، وهي عناصر
</p>

<div>
	خاضعة للتنسيق كالتالي:
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5151_57" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Page</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> styled</span><span class="pun">.</span><span class="pln">div</span><span class="pun">`</span><span class="pln">
  padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1em</span><span class="pun">;</span><span class="pln">
  background</span><span class="pun">:</span><span class="pln"> papayawhip</span><span class="pun">;</span><span class="pln">
</span><span class="pun">`</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Navigation</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> styled</span><span class="pun">.</span><span class="pln">div</span><span class="pun">`</span><span class="pln">
  background</span><span class="pun">:</span><span class="pln"> </span><span class="typ">BurlyWood</span><span class="pun">;</span><span class="pln">
  padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1em</span><span class="pun">;</span><span class="pln">
</span><span class="pun">`</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Footer</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> styled</span><span class="pun">.</span><span class="pln">div</span><span class="pun">`</span><span class="pln">
  background</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Chocolate</span><span class="pun">;</span><span class="pln">
  padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1em</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1em</span><span class="pun">;</span><span class="pln">
</span><span class="pun">`</span></pre>

	<p>
		لنستخدم هذه المكوّنات في التطبيق:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5151_59" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">Page</span><span class="pun">&gt;</span><span class="pln">      
      </span><span class="pun">&lt;</span><span class="typ">Navigation</span><span class="pun">&gt;</span><span class="pln">        
      </span><span class="pun">&lt;</span><span class="typ">Link</span><span class="pln"> style</span><span class="pun">={</span><span class="pln">padding</span><span class="pun">}</span><span class="pln"> to</span><span class="pun">=</span><span class="str">"/"</span><span class="pun">&gt;</span><span class="pln">home</span><span class="pun">&lt;/</span><span class="typ">Link</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">Link</span><span class="pln"> style</span><span class="pun">={</span><span class="pln">padding</span><span class="pun">}</span><span class="pln"> to</span><span class="pun">=</span><span class="str">"/notes"</span><span class="pun">&gt;</span><span class="pln">notes</span><span class="pun">&lt;/</span><span class="typ">Link</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">Link</span><span class="pln"> style</span><span class="pun">={</span><span class="pln">padding</span><span class="pun">}</span><span class="pln"> to</span><span class="pun">=</span><span class="str">"/users"</span><span class="pun">&gt;</span><span class="pln">users</span><span class="pun">&lt;/</span><span class="typ">Link</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">user
          </span><span class="pun">?</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">em</span><span class="pun">&gt;{</span><span class="pln">user</span><span class="pun">}</span><span class="pln"> logged in</span><span class="pun">&lt;/</span><span class="pln">em</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">:</span><span class="pln"> </span><span class="pun">&lt;</span><span class="typ">Link</span><span class="pln"> style</span><span class="pun">={</span><span class="pln">padding</span><span class="pun">}</span><span class="pln"> to</span><span class="pun">=</span><span class="str">"/login"</span><span class="pun">&gt;</span><span class="pln">login</span><span class="pun">&lt;/</span><span class="typ">Link</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="typ">Navigation</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Switch</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">Route</span><span class="pln"> path</span><span class="pun">=</span><span class="str">"/notes/:id"</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Note</span><span class="pln"> note</span><span class="pun">={</span><span class="pln">note</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="typ">Route</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">Route</span><span class="pln"> path</span><span class="pun">=</span><span class="str">"/notes"</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Notes</span><span class="pln"> notes</span><span class="pun">={</span><span class="pln">notes</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="typ">Route</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">Route</span><span class="pln"> path</span><span class="pun">=</span><span class="str">"/users"</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">{</span><span class="pln">user </span><span class="pun">?</span><span class="pln"> </span><span class="pun">&lt;</span><span class="typ">Users</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="pun">&lt;</span><span class="typ">Redirect</span><span class="pln"> to</span><span class="pun">=</span><span class="str">"/login"</span><span class="pln"> </span><span class="pun">/&gt;}</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="typ">Route</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">Route</span><span class="pln"> path</span><span class="pun">=</span><span class="str">"/login"</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Login</span><span class="pln"> onLogin</span><span class="pun">={</span><span class="pln">login</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="typ">Route</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">Route</span><span class="pln"> path</span><span class="pun">=</span><span class="str">"/"</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Home</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="typ">Route</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="typ">Switch</span><span class="pun">&gt;</span><span class="pln">

      </span><span class="pun">&lt;</span><span class="typ">Footer</span><span class="pun">&gt;</span><span class="pln">        
            </span><span class="pun">&lt;</span><span class="pln">em</span><span class="pun">&gt;</span><span class="typ">Note</span><span class="pln"> app</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Department</span><span class="pln"> of </span><span class="typ">Computer</span><span class="pln"> </span><span class="typ">Science</span><span class="pln"> </span><span class="lit">2020</span><span class="pun">&lt;/</span><span class="pln">em</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="typ">Footer</span><span class="pun">&gt;</span><span class="pln">    
   </span><span class="pun">&lt;/</span><span class="typ">Page</span><span class="pun">&gt;</span><span class="pln">  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

	<p>
		ستظهر النتيجة كالتالي:
	</p>

	<p style="text-align: center;">
		<img alt="styled_component_15.png" class="ipsImage ipsImage_thumbnailed" data-fileid="59654" data-unique="l2o749399" src="https://academy.hsoub.com/uploads/monthly_2021_03/styled_component_15.png.086dfe28bd92957e759a55f9a99d25c4.png"></p>

	<p>
		تزداد شعبية هذه المكتبة في الآونة الأخيرة، وقد اعتبرها العديد من المطورين بأنها أفضل الطرق في تنسيق تطبيقات React.
	</p>

	<h2>
		التمارين
	</h2>

	<p>
		يمكن أن تجد التمارين التي تتعلق بمواضيع هذا الفصل، في الفصل الأخير من هذا القسم ضمن مجموعة التمارين (توسيع تطبيق قائمة المدونات).
	</p>

	<p>
		ترجمة -وبتصرف- للفصل <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://fullstackopen.com/en/part7/more_about_styles" rel="external nofollow">More About Styles</a> من سلسلة <a data-ss1615737933="1" data-ss1615738511="1" data-ss1615738714="1" href="https://fullstackopen.com/en/" rel="external nofollow">Deep Dive Into Modern Web Development</a>
	</p>
</div>
]]></description><guid isPermaLink="false">1168</guid><pubDate>Sun, 14 Mar 2021 16:22:09 +0000</pubDate></item><item><title>&#x625;&#x646;&#x634;&#x627;&#x621; &#x62E;&#x637;&#x627;&#x641;&#x627;&#x62A; &#x645;&#x62E;&#x635;&#x635;&#x629; (Custom Hooks) &#x641;&#x64A; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; React</title><link>https://academy.hsoub.com/programming/javascript/react/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AE%D8%B7%D8%A7%D9%81%D8%A7%D8%AA-%D9%85%D8%AE%D8%B5%D8%B5%D8%A9-custom-hooks-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-react-r1167/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_03/604e2a3351f70_---(Custom-Hooks)---React.png.7813471a0e180432bb058519a2af5c70.png" /></p>

<p>
	ستختلف التمارين في هذا القسم عن تمارين القسم السابق. فستجد في هذا الفصل وفي الفصل الذي سبقه تمارين تتعلق بالأفكار التي سنقدمها في هذا الفصل، بالإضافة إلى سلسلة من التمارين التي سنراجع من خلالها ما تعلمناه خلال تقدمنا في مادة المنهاج، وذلك بتعديل التطبيق Bloglist الذي عملنا عليه في <a data-ss1615736263="1" href="https://academy.hsoub.com/programming/javascript/nodejs/%D9%87%D9%8A%D9%83%D9%84-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%AE%D9%84%D9%81%D9%8A%D8%A9-%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%A7%D8%AE%D8%AA%D8%A8%D8%A7%D8%B1%D8%A7%D8%AA-unit-tests-r1132/" rel="">القسم 4</a> و<a data-ss1615736263="1" href="https://academy.hsoub.com/programming/javascript/react/%D8%AA%D8%B3%D8%AC%D9%8A%D9%84-%D8%A7%D9%84%D8%AF%D8%AE%D9%88%D9%84-%D9%81%D9%8A-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%A3%D9%85%D8%A7%D9%85%D9%8A%D8%A9-r1136/" rel="">القسم 5</a> ومراجعته وتطبيق المهارات التي تعلمناها.
</p>

<h2>
	الخطافات
</h2>

<p>
	تقدم المكتبة React 10 أنواع من <a data-ss1615735338="1" data-ss1615736263="1" href="https://wiki.hsoub.com/React/hooks_reference" rel="external">الخطافات المدمجة</a>، من أكثرها شهرة <a data-ss1615735338="1" data-ss1615736263="1" href="https://wiki.hsoub.com/React/hooks_reference#useState" rel="external">useState</a> و<a data-ss1615735338="1" data-ss1615736263="1" href="https://wiki.hsoub.com/React/hooks_reference#useEffect" rel="external">useEffect</a> والتي استخدمناها كثيرًا. كما استخدمنا في <a data-ss1615736263="1" href="https://academy.hsoub.com/programming/javascript/react/%D8%AA%D8%B3%D8%AC%D9%8A%D9%84-%D8%A7%D9%84%D8%AF%D8%AE%D9%88%D9%84-%D9%81%D9%8A-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%A3%D9%85%D8%A7%D9%85%D9%8A%D8%A9-r1136/" rel="">القسم 5</a> الخطاف <a data-ss1615735338="1" data-ss1615736263="1" href="https://wiki.hsoub.com/React/hooks_reference#useImperativeHandle" rel="external">useImperativeHandle</a> والذي يسمح للمكوّنات بتقديم الدوال الخاصة بها إلى مكوّنات أخرى.
</p>

<p>
	بدأت مكتبات React خلال السنتين الماضيتين بتقديم واجهات برمجية مبنية على الخطافات. فقد استخدمنا في القسم السابق الخطافين <a data-ss1615735338="1" data-ss1615736263="1" href="https://react-redux.js.org/api/hooks#useselector" rel="external nofollow">useSelector</a> و<a data-ss1615735338="1" data-ss1615736263="1" href="https://react-redux.js.org/api/hooks#usedispatch" rel="external nofollow">useDispatch</a> من المكتبة React-Redux لمشاركة مخزن Redux وإيفاد الدوال إلى المكوّنات. فواجهة Redux البرمجية المبنية على الخطافات أسهل استعمالًا من سابقتها التي لازالت قيد الاستعمال <a data-ss1615735338="1" data-ss1615736263="1" href="https://academy.hsoub.com/programming/javascript/react/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D8%AF%D8%A7%D9%84%D8%A9-connect-%D9%81%D9%8A-redux-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-react-r1165/" rel="">connect</a>.
</p>

<p>
	تعتبر الواجهة البرمجية <a data-ss1615735338="1" data-ss1615736263="1" href="https://reacttraining.com/react-router/web/guides" rel="external nofollow">React-router</a> التي قدمناها في الفصل السابق مبنية جزئيًا على أساس <a data-ss1615735338="1" data-ss1615736263="1" href="ttps://reacttraining.com/react-router/web/api/Hooks" rel="external nofollow">الخطافات</a>. حيث تُستعمل خطافاتها للولوج إلى معاملات العناوين وكائن المحفوظات، وتعديل العنوان على المتصفح برمجيًا.
</p>

<p>
	لا تعتبر الخطافات دوال عادية كما ذكرنا في القسم 1، ولابد من الخضوع إلى مجموعة من <a data-ss1615735338="1" data-ss1615736263="1" href="https://wiki.hsoub.com/React/hooks_rules" rel="external">القواعد</a>. لنستحضر تلك القوانين التي نسخناها حرفيًا من توثيق React:
</p>

<p>
	<strong>لا تستدعي الخطافات من داخل الحلقات أو العبارات الشرطية أو الدوال المتداخلة</strong>، بل استخدمها دائمًا عند أعلى مستويات دالة React.
</p>

<p>
	<strong>لا تستدعي الخطافات من داخل دول JavaScript النظامية</strong>، بل يمكنك أن:
</p>

<ul>
<li>
		<p>
			استدعاء الخطافات من مكوّنات دوال React
		</p>
	</li>
	<li>
		استدعاء الخطافات من قبل خطافات مخصصة.
	</li>
</ul>
<p>
	هنالك قاعدة يقدمها المدقق <a data-ss1615735338="1" data-ss1615736263="1" href="https://www.npmjs.com/package/eslint-plugin-react-hooks" rel="external nofollow">ESlint</a> للتأكد من استدعاء الخطافات بالشكل الصحيح، حيث تُهيئ التطبيقات المبنية بواسطة create-react-app القاعدة <a data-ss1615735338="1" data-ss1615736263="1" href="https://www.npmjs.com/package/eslint-plugin-react-hooks" rel="external nofollow">eslint-plugin-react-hooks</a> بشكل دائم، لكي تنبهك عند استعمال الخطاف بطريقة غير مشروعة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="59635" data-ss1615735338="1" data-ss1615736263="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/eslint_hooks_use_error_01.png.7d2d3d3b6fa3e7a02b4c1cab4ef120d1.png" rel=""><img alt="eslint_hooks_use_error_01.png" class="ipsImage ipsImage_thumbnailed" data-fileid="59635" data-unique="jeapb6wr2" src="https://academy.hsoub.com/uploads/monthly_2021_03/eslint_hooks_use_error_01.png.7d2d3d3b6fa3e7a02b4c1cab4ef120d1.png"></a>
</p>

<h2>
	خطافات مخصصة
</h2>

<p>
	تقدم لك Recat ميزة إنشاء خطافات <a data-ss1615735338="1" data-ss1615736263="1" href="https://wiki.hsoub.com/React/hooks_custom" rel="external">خاصة</a> بك. وتعتبر React أن الغرض الرئيسي من هذه الخطافات هو تسهيل إعادة استخدام شيفرة مكوّن في مكان آخر.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p>
		يمكّنك بناء خطافاتك الخاصة من نقل منطق المكوّن إلى دوال قابلة للاستخدام مرة أخرى.
	</p>
</blockquote>

<p>
	إنّ الخطافات المخصصة هي دوال JavaScript نظامية يمكنها استعمال أية خطافات أخرى طالما أنها تخضع لقواعد استخدام الخطافات. بالإضافة إلى ضرورة أن يبدأ اسم الخطاف بالكلمة "use".
</p>

<p>
	لقد أنشأنا في <a data-ss1615735338="1" data-ss1615736263="1" href="https://academy.hsoub.com/programming/javascript/react/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-react-r1072/" rel="">القسم 1</a> تطبيق عداد يمكن زيادة قيمته أو إنقاصها أو تصفيره. وكانت شيفرته كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6713_9" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> useState </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">counter</span><span class="pun">,</span><span class="pln"> setCounter</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;{</span><span class="pln">counter</span><span class="pun">}&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setCounter</span><span class="pun">(</span><span class="pln">counter </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)}&gt;</span><span class="pln">
        plus
      </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setCounter</span><span class="pun">(</span><span class="pln">counter </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)}&gt;</span><span class="pln">
        minus
      </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">      
      </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setCounter</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)}&gt;</span><span class="pln">
        zero
      </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لننقل منطق العداد ونضعه ضمن خطاف مخصص. ستبدو شيفرة الخطاف كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6713_11" style="">
<span class="kwd">const</span><span class="pln"> useCounter </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">value</span><span class="pun">,</span><span class="pln"> setValue</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> increase </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    setValue</span><span class="pun">(</span><span class="pln">value </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> decrease </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    setValue</span><span class="pun">(</span><span class="pln">value </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> zero </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    setValue</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    value</span><span class="pun">,</span><span class="pln"> 
    increase</span><span class="pun">,</span><span class="pln">
    decrease</span><span class="pun">,</span><span class="pln">
    zero
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يستخدم الخطاف المخصص خطافًا آخر هو <code>useState</code>. يعيد الخطاف كائنًا تتضمن خصائصه قيمة العداد بالإضافة إلى دوال لتغيير هذه القيمة.
</p>

<p>
	يمكن أن يستخدم تطبيق React هذا الخطاف كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6713_13" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> counter </span><span class="pun">=</span><span class="pln"> useCounter</span><span class="pun">()</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;{</span><span class="pln">counter</span><span class="pun">.</span><span class="pln">value</span><span class="pun">}&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">counter</span><span class="pun">.</span><span class="pln">increase</span><span class="pun">}&gt;</span><span class="pln">
        plus
      </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">counter</span><span class="pun">.</span><span class="pln">decrease</span><span class="pun">}&gt;</span><span class="pln">
        minus
      </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">      
      </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">counter</span><span class="pun">.</span><span class="pln">zero</span><span class="pun">}&gt;</span><span class="pln">
        zero
      </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وهكذا يمكننا نقل حالة المكون <code>App</code> ومنطق التعامل معه إلى الخطاف <code>useCounterhook</code>. وسيتولى هذا الخطاف التعامل مع حالة ومنطق التطبيق. يمكن إعادة استخدام هذا الخطاف في التطبيق الذي يراقب عدد نقرات الزر الأيمن والأيسر للفأرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6713_15" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> left </span><span class="pun">=</span><span class="pln"> useCounter</span><span class="pun">()</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> right </span><span class="pun">=</span><span class="pln"> useCounter</span><span class="pun">()</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">left</span><span class="pun">.</span><span class="pln">value</span><span class="pun">}</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">left</span><span class="pun">.</span><span class="pln">increase</span><span class="pun">}&gt;</span><span class="pln">
        left
      </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">right</span><span class="pun">.</span><span class="pln">increase</span><span class="pun">}&gt;</span><span class="pln">
        right
      </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">right</span><span class="pun">.</span><span class="pln">value</span><span class="pun">}</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يُنشئ التطبيق عدادين منفصلين تمامًا. يُسند الأول إلى المتغيّر <code>left</code> ويُسند الثاني إلى المتغير <code>right</code>.
</p>

<p>
	يصعب التعامل أحيانًا مع نماذج React. يستخدم التطبيق التالي نموذجًا يطلب من المستخدم أن يُدخل اسمه وتاريخ ميلاده وطوله:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6713_17" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> setName</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">born</span><span class="pun">,</span><span class="pln"> setBorn</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">height</span><span class="pun">,</span><span class="pln"> setHeight</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
        name</span><span class="pun">:</span><span class="pln"> 
        </span><span class="pun">&lt;</span><span class="pln">input
          type</span><span class="pun">=</span><span class="str">'text'</span><span class="pln">
          value</span><span class="pun">={</span><span class="pln">name</span><span class="pun">}</span><span class="pln">
          onChange</span><span class="pun">={(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setName</span><span class="pun">(</span><span class="pln">event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">value</span><span class="pun">)}</span><span class="pln"> 
        </span><span class="pun">/&gt;</span><span class="pln"> 
        </span><span class="pun">&lt;</span><span class="pln">br</span><span class="pun">/&gt;</span><span class="pln"> 
        birthdate</span><span class="pun">:</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">input
          type</span><span class="pun">=</span><span class="str">'date'</span><span class="pln">
          value</span><span class="pun">={</span><span class="pln">born</span><span class="pun">}</span><span class="pln">
          onChange</span><span class="pun">={(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setBorn</span><span class="pun">(</span><span class="pln">event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">value</span><span class="pun">)}</span><span class="pln">
        </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">br </span><span class="pun">/&gt;</span><span class="pln"> 
        height</span><span class="pun">:</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">input
          type</span><span class="pun">=</span><span class="str">'number'</span><span class="pln">
          value</span><span class="pun">={</span><span class="pln">height</span><span class="pun">}</span><span class="pln">
          onChange</span><span class="pun">={(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setHeight</span><span class="pun">(</span><span class="pln">event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">value</span><span class="pun">)}</span><span class="pln">
        </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">name</span><span class="pun">}</span><span class="pln"> </span><span class="pun">{</span><span class="pln">born</span><span class="pun">}</span><span class="pln"> </span><span class="pun">{</span><span class="pln">height</span><span class="pun">}</span><span class="pln"> 
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لكل حقل من النموذج حالته الخاصة. ولكي نبقي حالة النموذج متزامنة مع ما يدخله المستخدم، لابدّ من تعريف معالجًا مناسبًا للحدث <code>onChange</code> للتعامل مع التغيرات في عناصر الدخل.
</p>

<p>
	لنعرّف الخطاف المخصص <code>useFieldhook</code> الذي سيسهل إدارة حالة النموذج:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6713_19" style="">
<span class="kwd">const</span><span class="pln"> useField </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">type</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">value</span><span class="pun">,</span><span class="pln"> setValue</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> onChange </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    setValue</span><span class="pun">(</span><span class="pln">event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">value</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">,</span><span class="pln">
    value</span><span class="pun">,</span><span class="pln">
    onChange
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تتلقى دالة الخطاف نوع حقل الدخل (مربع النص) كمعامل. وتعيد الدالة كل الصفات التي يتطلبها عنصر الدخل، وهي نوعه وقيمته ومعالج الحدث <code>onChange</code>.
</p>

<p>
	يمكن استخدام الخطاف بالطريقة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6713_21" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> name </span><span class="pun">=</span><span class="pln"> useField</span><span class="pun">(</span><span class="str">'text'</span><span class="pun">)</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">input
          type</span><span class="pun">={</span><span class="pln">name</span><span class="pun">.</span><span class="pln">type</span><span class="pun">}</span><span class="pln">
          value</span><span class="pun">={</span><span class="pln">name</span><span class="pun">.</span><span class="pln">value</span><span class="pun">}</span><span class="pln">
          onChange</span><span class="pun">={</span><span class="pln">name</span><span class="pun">.</span><span class="pln">onChange</span><span class="pun">}</span><span class="pln"> 
        </span><span class="pun">/&gt;</span><span class="pln"> 
        </span><span class="com">// ...</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	نشر الصفات
</h2>

<p>
	يمكننا تسهيل الأمور أكثر. يحتوي الكائن <code>name</code> على كل الصفات التي يحتاجها عنصر الدخل من خصائص هذا الكائن، وبالتالي يمكننا تمرير هذه الخصائص إلى العنصر باستخدام <a data-ss1615735338="1" data-ss1615736263="1" href="https://wiki.hsoub.com/React/jsx_in_depth#.D8.AE.D8.A7.D8.B5.D9.8A.D9.91.D8.A7.D8.AA_.D8.A7.D9.84.D9.86.D8.B4.D8.B1" rel="external">عبارة النشر</a> كالتالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6713_23" style="">
<span class="tag">&lt;input</span><span class="pln"> {...</span><span class="atn">name</span><span class="pln">} </span><span class="tag">/&gt;</span><span class="pln"> </span></pre>

<p>
	وكما ستجد في <a data-ss1615735338="1" data-ss1615736263="1" href="https://wiki.hsoub.com/React/jsx_in_depth#.D8.AE.D8.A7.D8.B5.D9.8A.D9.91.D8.A7.D8.AA_.D8.A7.D9.84.D9.86.D8.B4.D8.B1" rel="external">المثال</a> الموجود ضمن توثيق React، سيعطي استخدام أي من الطريقتين التاليتين في تمرير الخصائص النتيجة نفسها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6713_25" style="">
<span class="pun">&lt;</span><span class="typ">Greeting</span><span class="pln"> firstName</span><span class="pun">=</span><span class="str">'Arto'</span><span class="pln"> lastName</span><span class="pun">=</span><span class="str">'Hellas'</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> person </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  firstName</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Arto'</span><span class="pun">,</span><span class="pln">
  lastName</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Hellas'</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">&lt;</span><span class="typ">Greeting</span><span class="pln"> </span><span class="pun">{...</span><span class="pln">person</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span></pre>

<p>
	يمكن تبسيط التطبيق إلى الشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6713_27" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> name </span><span class="pun">=</span><span class="pln"> useField</span><span class="pun">(</span><span class="str">'text'</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> born </span><span class="pun">=</span><span class="pln"> useField</span><span class="pun">(</span><span class="str">'date'</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> height </span><span class="pun">=</span><span class="pln"> useField</span><span class="pun">(</span><span class="str">'number'</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
        name</span><span class="pun">:</span><span class="pln"> 
        </span><span class="pun">&lt;</span><span class="pln">input  </span><span class="pun">{...</span><span class="pln">name</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln"> 
        </span><span class="pun">&lt;</span><span class="pln">br</span><span class="pun">/&gt;</span><span class="pln"> 
        birthdate</span><span class="pun">:</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">input </span><span class="pun">{...</span><span class="pln">born</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">br </span><span class="pun">/&gt;</span><span class="pln"> 
        height</span><span class="pun">:</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">input </span><span class="pun">{...</span><span class="pln">height</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">name</span><span class="pun">.</span><span class="pln">value</span><span class="pun">}</span><span class="pln"> </span><span class="pun">{</span><span class="pln">born</span><span class="pun">.</span><span class="pln">value</span><span class="pun">}</span><span class="pln"> </span><span class="pun">{</span><span class="pln">height</span><span class="pun">.</span><span class="pln">value</span><span class="pun">}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيسهل استخدام النماذج عندما نستخدم الخطافات المخصصة في تغليف بعض التفاصيل المزعجة المتعلقة بمزامنة الحالة.
</p>

<p>
	ومن الواضح أنّ الخطافات المخصصة ليست فقط أداة لإعادة استخدام الشيفرة، بل تقدم طرق أفضل في تقسيم شيفرتنا إلى وحدات أصغر.
</p>

<h2>
	المزيد حول الخطافات
</h2>

<p>
	يمكنك الرجوع إلى <a data-ss1615735338="1" data-ss1615736263="1" href="https://wiki.hsoub.com/React#.D8.A7.D9.84.D8.AE.D8.B7.D8.A7.D9.81.D8.A7.D8.AA" rel="external">قسم الخطافات</a> في موسوعة حسوب ففيه كل ما تحتاج إلى معرفته حول الخطافات بلغة عربية ومع أمثلة عملية ويمكنك الاستزادة من هذه المصادر الأجنبية التي تستحق الاطلاع:
</p>

<ul>
<li>
		<a data-ss1615735338="1" data-ss1615736263="1" href="https://github.com/rehooks/awesome-react-hooks" rel="external nofollow">Awesome React Hooks Resources</a>
	</li>
	<li>
		<a data-ss1615735338="1" data-ss1615736263="1" href="https://usehooks.com/" rel="external nofollow">Easy to understand React Hook recipes by Gabe Ragland</a>
	</li>
	<li>
		<a data-ss1615735338="1" data-ss1615736263="1" href="https://overreacted.io/why-do-hooks-rely-on-call-order/" rel="external nofollow">Why Do React Hooks Rely on Call Order</a>
	</li>
</ul>
<h2>
	التمارين 7.4 - 7.8
</h2>

<p>
	سنستمر في العمل على التطبيق الذي ورد في تمارين الفصل السابق React-Router من هذا القسم.
</p>

<h3>
	7.4 تطبيق الطرائف باستعمال الخطافات: الخطوة 1
</h3>

<p>
	بسط عملية إنشاء طرفة جديدة من خلال النموذج في تطبيقك باستعمال الخطاف المخصص <code>useFieldhook</code> الذي عرفناه سابقًا.
</p>

<p>
	المكان الطبيعي لحفظ الخطاف المخصص في تطبيقك قد يكون الملف "src/hooks/index.js/".
</p>

<p>
	وانتبه عند استخدام <a data-ss1615735338="1" data-ss1615736263="1" href="https://wiki.hsoub.com/JavaScript/export" rel="external">التصدير المحدد</a> بدلًا من الافتراضي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6713_33" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> useState </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> useField </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">type</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">value</span><span class="pun">,</span><span class="pln"> setValue</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> onChange </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    setValue</span><span class="pun">(</span><span class="pln">event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">value</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">,</span><span class="pln">
    value</span><span class="pun">,</span><span class="pln">
    onChange
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// modules can have several named exports</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> useAnotherHook </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	فستتغير طريقة <a data-ss1615735338="1" data-ss1615736263="1" href="https://wiki.hsoub.com/JavaScript/import" rel="external">إدراج</a> الخطاف إلى الشكل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6713_31" style="">
<span class="kwd">import</span><span class="pln">  </span><span class="pun">{</span><span class="pln"> useField </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'./hooks'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> username </span><span class="pun">=</span><span class="pln"> useField</span><span class="pun">(</span><span class="str">'text'</span><span class="pun">)</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<h3>
	7.5 تطبيق الطرائف باستعمال الخطافات: الخطوة 2
</h3>

<p>
	أضف زرًا إلى النموذج بحيث يمكنك مسح كل المعلومات في عناصر الإدخال:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="59631" data-ss1615735338="1" data-ss1615736263="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/anecdotes_clearr_all_02.png.39ccb9bed933ee3c722dd221e3db8d8a.png" rel=""><img alt="anecdotes_clearr_all_02.png" class="ipsImage ipsImage_thumbnailed" data-fileid="59631" data-unique="1qi8xbwlc" src="https://academy.hsoub.com/uploads/monthly_2021_03/anecdotes_clearr_all_02.png.39ccb9bed933ee3c722dd221e3db8d8a.png"></a>
</p>

<p>
	وسع وظيفة الخطاف <code>useFieldhook</code> لكي يقدم طريقة لمسح كل بيانات حقول النموذج.
</p>

<p>
	وتبعًا لحلك المقترح قد تجد نفسك أمام التحذير التالي على الطرفية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="59634" data-ss1615735338="1" data-ss1615736263="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/custom_hook_warn_03.png.830cb3e67479811d17c48b30f64a5745.png" rel=""><img alt="custom_hook_warn_03.png" class="ipsImage ipsImage_thumbnailed" data-fileid="59634" data-unique="108odrlkb" src="https://academy.hsoub.com/uploads/monthly_2021_03/custom_hook_warn_03.png.830cb3e67479811d17c48b30f64a5745.png"></a>
</p>

<p>
	سنعود إلى هذا التحذير في التمرين التالي.
</p>

<h3>
	7.6 تطبيق الطرائف باستعمال الخطافات: الخطوة 3
</h3>

<p>
	إن لم يظهر التحذير السابق في حلك فقد أنجزت بالفعل حل هذا التمرين.
</p>

<p>
	إن ظهر معك ذلك التحذير فعليك إجراء التعديلات المناسبة للتخلص من القيمة غير المناسبة للخاصية <code>reset</code> ضمن المعرّف &lt;input&gt;.
</p>

<p>
	إنّ سبب هذا التحذير هو أن تعديل التطبيق ليستعمل نشر الصفات كالتالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6713_35" style="">
<span class="tag">&lt;input</span><span class="pln"> {...</span><span class="atn">content</span><span class="pln">}</span><span class="tag">/&gt;</span></pre>

<p>
	مطابق تمامًا للشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6713_39" style="">
<span class="tag">&lt;input</span><span class="pln">
  </span><span class="atn">value</span><span class="pun">=</span><span class="atv">{content.value}</span><span class="pln"> 
  </span><span class="atn">type</span><span class="pun">=</span><span class="atv">{content.type}</span><span class="pln">
  </span><span class="atn">onChange</span><span class="pun">={</span><span class="pln">content</span><span class="pun">.</span><span class="pln">onChange</span><span class="pun">}</span><span class="pln">
  </span><span class="atn">reset</span><span class="pun">=</span><span class="atv">{content.reset}</span><span class="pln">
</span><span class="tag">/&gt;</span></pre>

<p>
	لكن لا يجب أن نسند الصفة <code>reset</code> إلى عنصر الإدخال <code>input</code>. إنّ أحد الحلول المقترحة هو عدم استعمال صيغة النشر وكتابة الصفات كالتالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6713_41" style="">
<span class="tag">&lt;input</span><span class="pln">
  </span><span class="atn">value</span><span class="pun">=</span><span class="atv">{username.value}</span><span class="pln"> 
  </span><span class="atn">type</span><span class="pun">=</span><span class="atv">{username.type}</span><span class="pln">
  </span><span class="atn">onChange</span><span class="pun">={</span><span class="pln">username</span><span class="pun">.</span><span class="pln">onChange</span><span class="pun">}</span><span class="pln">
</span><span class="tag">/&gt;</span></pre>

<p>
	إن كنت ستستخدم هذا الحل فستخسر العديد من الميزات التي يقدمها الخطاف <code>useFieldhook</code>. فكّر بدلًا من ذلك بحل يستخدم طريقة النشر.
</p>

<h3>
	7.7 خطاف لتطبيق الدول:
</h3>

<p>
	لنعد إلى التمارين 12 إلى 14 من القسم 2.
</p>

<p>
	استعمل الشيفرة الموجودة على <a data-ss1615735338="1" data-ss1615736263="1" href="https://github.com/fullstack-hy2020/country-hook" rel="external nofollow">GitHub</a> كقاعدة انطلاق.
</p>

<p>
	يُستخدم التطبيق للبحث عن تفاصيل دولة محددة بالاستعانة بالواجهة <a data-ss1615735338="1" data-ss1615736263="1" href="https://restcountries.eu." ipsnoembed="false" rel="external nofollow">https://restcountries.eu.</a> فإن عُثر على الدولة ستُعرض معلوماتها على الشاشة.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="59632" data-ss1615735338="1" data-ss1615736263="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/country_hook_04.png.a8c08e3ee9898f334af810c60f306109.png" rel=""><img alt="country_hook_04.png" class="ipsImage ipsImage_thumbnailed" data-fileid="59632" data-unique="fvo1o12pt" src="https://academy.hsoub.com/uploads/monthly_2021_03/country_hook_04.png.a8c08e3ee9898f334af810c60f306109.png"></a>
</p>

<p>
	وإن لم يُعثر على الدولة ستظهر رسالة تبلغ فيها المستخدم بذلك.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="59633" data-ss1615735338="1" data-ss1615736263="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/country_not_founr_05.png.5661411a7bb1e5318fe18474f847f1d9.png" rel=""><img alt="country_not_founr_05.png" class="ipsImage ipsImage_thumbnailed" data-fileid="59633" data-unique="hotjuyzj7" src="https://academy.hsoub.com/uploads/monthly_2021_03/country_not_founr_05.png.5661411a7bb1e5318fe18474f847f1d9.png"></a>
</p>

<p>
	إنّ التطبيق السابق مكتمل وجاهز للعمل، لكن عليك في هذه التمرين إنشاء خطاف مخصص باسم <code>useCountry</code> يستخدم للبحث عن تفاصيل الدولة التي تُمرر إلى الخطاف كمعامل.
</p>

<p>
	استخدم الوصلة <a data-ss1615735338="1" data-ss1615736263="1" href="https://restcountries.eu/#api-endpoints-full-name" rel="external nofollow">full name</a> من الواجهة البرمجية السابقة لإحضار بيانات الدولة مستخدمًا الخطاف <code>useEffect</code> ضمن خطافك المخصص. ولاحظ أنه من الضروري استخدام مصفوفة <a data-ss1615735338="1" data-ss1615736263="1" href="https://wiki.hsoub.com/React/hooks_reference#.D8.AA.D9.86.D9.81.D9.8A.D8.B0_.D8.AA.D8.A3.D8.AB.D9.8A.D8.B1_.D8.B4.D8.B1.D8.B7.D9.8A.D9.8B.D9.91.D8.A7" rel="external">المعامل الثاني</a> للخطاف <code>useEffect</code> في هذا التمرين للتحكم بتوقيت تنفيذ دالة المؤثر.
</p>

<h3>
	7.8 الخطافات الكاملة
</h3>

<p>
	ستبدو الشيفرة المسؤولة عن الاتصال مع الواجهة الخلفية لتطبيق الملاحظات من القسم السابق على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6713_43" style="">
<span class="kwd">import</span><span class="pln"> axios from </span><span class="str">'axios'</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> baseUrl </span><span class="pun">=</span><span class="pln"> </span><span class="str">'/api/notes'</span><span class="pln">

let token </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> setToken </span><span class="pun">=</span><span class="pln"> newToken </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  token </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">bearer $</span><span class="pun">{</span><span class="pln">newToken</span><span class="pun">}`</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> getAll </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> request </span><span class="pun">=</span><span class="pln"> axios</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="pln">baseUrl</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> request</span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> create </span><span class="pun">=</span><span class="pln"> async newObject </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> config </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    headers</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Authorization</span><span class="pun">:</span><span class="pln"> token </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> response </span><span class="pun">=</span><span class="pln"> await axios</span><span class="pun">.</span><span class="pln">post</span><span class="pun">(</span><span class="pln">baseUrl</span><span class="pun">,</span><span class="pln"> newObject</span><span class="pun">,</span><span class="pln"> config</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> update </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">id</span><span class="pun">,</span><span class="pln"> newObject</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> request </span><span class="pun">=</span><span class="pln"> axios</span><span class="pun">.</span><span class="pln">put</span><span class="pun">(`</span><span class="pln">$</span><span class="pun">{</span><span class="pln"> baseUrl </span><span class="pun">}</span><span class="pln"> </span><span class="pun">/</span><span class="pln">$</span><span class="pun">{</span><span class="pln">id</span><span class="pun">}`,</span><span class="pln"> newObject</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> request</span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> getAll</span><span class="pun">,</span><span class="pln"> create</span><span class="pun">,</span><span class="pln"> update</span><span class="pun">,</span><span class="pln"> setToken </span><span class="pun">}</span></pre>

<p>
	لا توحي الشيفرة السابقة أبدًا بأنّ تطبيقنا هو للتعامل مع الملاحظات. وباستثناء قيمة المتغير <code>baseUrl</code> يمكن استخدام الشيفرة السابقة مع تطبيق قائمة المدونات للاتصال مع الواجهة الخلفية.
</p>

<p>
	افصل شيفرة الاتصال مع الواجهة الخلفية ضمن خطاف مخصص لها باسم<code>useResource</code>. يكفي إحضار كل الموارد بالإضافة إلى إنشاء مورد جديد.
</p>

<p>
	يمكنك تنفيذ التمرين من أجل المشروع الموجود في المستودع <a data-ss1615735338="1" data-ss1615736263="1" href="https://github.com/fullstack-hy2020/ultimate-hooks" rel="external nofollow">https://github.com/fullstack-hy2020/ultimate-hooks</a>. للمكوّن <code>App</code> لهذا المشروع الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6713_45" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> content </span><span class="pun">=</span><span class="pln"> useField</span><span class="pun">(</span><span class="str">'text'</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> name </span><span class="pun">=</span><span class="pln"> useField</span><span class="pun">(</span><span class="str">'text'</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> number </span><span class="pun">=</span><span class="pln"> useField</span><span class="pun">(</span><span class="str">'text'</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">notes</span><span class="pun">,</span><span class="pln"> noteService</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useResource</span><span class="pun">(</span><span class="str">'http://localhost:3005/notes'</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">persons</span><span class="pun">,</span><span class="pln"> personService</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useResource</span><span class="pun">(</span><span class="str">'http://localhost:3005/persons'</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> handleNoteSubmit </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">
    noteService</span><span class="pun">.</span><span class="pln">create</span><span class="pun">({</span><span class="pln"> content</span><span class="pun">:</span><span class="pln"> content</span><span class="pun">.</span><span class="pln">value </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> handlePersonSubmit </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">
    personService</span><span class="pun">.</span><span class="pln">create</span><span class="pun">({</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> name</span><span class="pun">.</span><span class="pln">value</span><span class="pun">,</span><span class="pln"> number</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">.</span><span class="pln">value</span><span class="pun">})</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">notes</span><span class="pun">&lt;/</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">form onSubmit</span><span class="pun">={</span><span class="pln">handleNoteSubmit</span><span class="pun">}&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">input </span><span class="pun">{...</span><span class="pln">content</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">create</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">n </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">p key</span><span class="pun">={</span><span class="pln">n</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}&gt;{</span><span class="pln">n</span><span class="pun">.</span><span class="pln">content</span><span class="pun">}&lt;/</span><span class="pln">p</span><span class="pun">&gt;)}</span><span class="pln">

      </span><span class="pun">&lt;</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">persons</span><span class="pun">&lt;/</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">form onSubmit</span><span class="pun">={</span><span class="pln">handlePersonSubmit</span><span class="pun">}&gt;</span><span class="pln">
        name </span><span class="pun">&lt;</span><span class="pln">input </span><span class="pun">{...</span><span class="pln">name</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">br</span><span class="pun">/&gt;</span><span class="pln">
        number </span><span class="pun">&lt;</span><span class="pln">input </span><span class="pun">{...</span><span class="pln">number</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">create</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">persons</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">n </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">p key</span><span class="pun">={</span><span class="pln">n</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}&gt;{</span><span class="pln">n</span><span class="pun">.</span><span class="pln">name</span><span class="pun">}</span><span class="pln"> </span><span class="pun">{</span><span class="pln">n</span><span class="pun">.</span><span class="pln">number</span><span class="pun">}&lt;/</span><span class="pln">p</span><span class="pun">&gt;)}</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يعيد الخطاف المخصص مصفوفة من عنصرين كخطاف الحالة. يحتوي العنصر الأول على كل الموارد، بينما يمثل الآخر كائنًا يمكن استخدامه من أجل التغيير في مجموعة الموارد، كإنشاء مورد جديد.
</p>

<p>
	إن أضفت الخطاف بشكله الصحيح يمكنك إعادة استخدامه في تطبيق الملاحظات ودليل الهاتف (شغل الخادم باستعمال الأمر <code>npm run server</code> على المنفذ 3005).
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="59636" data-ss1615735338="1" data-ss1615736263="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/reuse_custom_hook_06.png.978d72f0c27288b2fe6c98b24efd954d.png" rel=""><img alt="reuse_custom_hook_06.png" class="ipsImage ipsImage_thumbnailed" data-fileid="59636" data-unique="an6mv5w33" src="https://academy.hsoub.com/uploads/monthly_2021_03/reuse_custom_hook_06.png.978d72f0c27288b2fe6c98b24efd954d.png"></a>
</p>

<p>
	ترجمة -وبتصرف- للفصل <a data-ss1615735338="1" data-ss1615736263="1" href="https://fullstackopen.com/en/part7/custom_hooks" rel="external nofollow">Custom hooks</a> من سلسلة <a data-ss1615735338="1" data-ss1615736263="1" href="https://fullstackopen.com/en/" rel="external nofollow">Deep Dive Into Modern Web Development</a>
</p>
]]></description><guid isPermaLink="false">1167</guid><pubDate>Sun, 14 Mar 2021 15:38:59 +0000</pubDate></item><item><title>&#x645;&#x62F;&#x62E;&#x644; &#x625;&#x644;&#x649; &#x627;&#x633;&#x62A;&#x639;&#x645;&#x627;&#x644; &#x627;&#x644;&#x645;&#x643;&#x62A;&#x628;&#x629; React-Router</title><link>https://academy.hsoub.com/programming/javascript/react/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D8%A7%D9%84%D9%85%D9%83%D8%AA%D8%A8%D8%A9-react-router-r1166/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_03/604e28b702e6c_----React-Router.png.051e2ca38f416f2586dbbd4628aaeaee.png" /></p>

<p>
	ستختلف التمارين قليلًا في القسم السابع من منهاج <a data-ss1615734954="1" href="https://academy.hsoub.com/tags/full_stack_101/" rel="">full_stack_101</a> عن ما سبقها. فستجد في هذا الفصل وفي الفصل الذي يليه تمارين تتعلق بالأفكار التي سنقدمها في هذا الفصل، بالإضافة إلى سلسلة من التمارين التي سنراجع من خلالها ما تعلمناه خلال تقدمنا في مادة المنهاج، وذلك بتوسيع التطبيق Bloglist الذي عملنا عليه في القسمين 4 و5.
</p>

<h2>
	هيكلية التنقل ضمن التطبيق
</h2>

<p>
	سنعود حاليًا إلى React دون استخدام Redux.
</p>

<p>
	من الشائع أن تحتوي التطبيقات إلى شريط تنقل يساعد على تغيير الصفحات التي يعرضها التطبيق. فيمكن أن يتضمن تطبيقنا صفحة رئيسية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-ss1615734954="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/app_home_page_01.png.de9587530b295de771162a4b2f7f8d24.png" data-fileid="59623" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="59623" data-unique="ia8lkknst" src="https://academy.hsoub.com/uploads/monthly_2021_03/app_home_page_01.png.de9587530b295de771162a4b2f7f8d24.png" alt="app_home_page_01.png"></a>
</p>

<p>
	وصفحات منفصلة لعرض معلومات عن الملاحظات والمستخدمين:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-ss1615734954="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/app_note_page_02.png.bebad46aee4bd056fa9b5ecf193ae199.png" data-fileid="59624" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="59624" data-unique="dmim2jqez" src="https://academy.hsoub.com/uploads/monthly_2021_03/app_note_page_02.png.bebad46aee4bd056fa9b5ecf193ae199.png" alt="app_note_page_02.png"></a>
</p>

<p>
	تتغير الصفحات التي يحتويها تطبيق <a data-ss1615734954="1" href="https://academy.hsoub.com/programming/javascript/react/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r1071/" rel="">وفقًا للمدرسة القديمة</a> باستخدام طلب HTTP-GET يرسله المتصفح إلى الخادم ومن ثم يصيّر شيفرة HTML التي تعرض الصفحة المُعادة.
</p>

<p>
	لكننا سنبقى عمليًا في نفس الصفحة في التطبيقات وحيدة الصفحة. حيث يوحي تنفيذ شيفرة JavaScript ضمن المتصفح بوجود عدة صفحات. فلو أرسل طلب HTTP عند تغيير الواجهة المعروضة، فهو فقط لإحضار البيانات بصيغة JSON والتي قد يحتاجها التطبيق لعرض الواجهة الجديدة.
</p>

<p>
	من السهل جدًا إضافة شريط التنقل أو عرض تطبيق بعدة واجهات استخدام React.
</p>

<p>
	تمثل الشيفرة التالية إحدى الطرق:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6684_8" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> useState </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">ReactDOM</span><span class="pln"> from </span><span class="str">'react-dom'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Home</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">TKTL notes app</span><span class="pun">&lt;</span><span class="str">/h2&gt; &lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Notes</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="typ">Notes</span><span class="pun">&lt;</span><span class="str">/h2&gt; &lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Users</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="typ">Users</span><span class="pun">&lt;</span><span class="str">/h2&gt; &lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">page</span><span class="pun">,</span><span class="pln"> setPage</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="str">'home'</span><span class="pun">)</span><span class="pln">

 </span><span class="kwd">const</span><span class="pln"> toPage </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">page</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">
    setPage</span><span class="pun">(</span><span class="pln">page</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> content </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">page </span><span class="pun">===</span><span class="pln"> </span><span class="str">'home'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">&lt;</span><span class="typ">Home</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">page </span><span class="pun">===</span><span class="pln"> </span><span class="str">'notes'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">&lt;</span><span class="typ">Notes</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">page </span><span class="pun">===</span><span class="pln"> </span><span class="str">'users'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">&lt;</span><span class="typ">Users</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> padding </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">a href</span><span class="pun">=</span><span class="str">""</span><span class="pln"> onClick</span><span class="pun">={</span><span class="pln">toPage</span><span class="pun">(</span><span class="str">'home'</span><span class="pun">)}</span><span class="pln"> style</span><span class="pun">={</span><span class="pln">padding</span><span class="pun">}&gt;</span><span class="pln">
          home
        </span><span class="pun">&lt;/</span><span class="pln">a</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">a href</span><span class="pun">=</span><span class="str">""</span><span class="pln"> onClick</span><span class="pun">={</span><span class="pln">toPage</span><span class="pun">(</span><span class="str">'notes'</span><span class="pun">)}</span><span class="pln"> style</span><span class="pun">={</span><span class="pln">padding</span><span class="pun">}&gt;</span><span class="pln">
          notes
        </span><span class="pun">&lt;/</span><span class="pln">a</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">a href</span><span class="pun">=</span><span class="str">""</span><span class="pln"> onClick</span><span class="pun">={</span><span class="pln">toPage</span><span class="pun">(</span><span class="str">'users'</span><span class="pun">)}</span><span class="pln"> style</span><span class="pun">={</span><span class="pln">padding</span><span class="pun">}&gt;</span><span class="pln">
          users
        </span><span class="pun">&lt;/</span><span class="pln">a</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">

      </span><span class="pun">{</span><span class="pln">content</span><span class="pun">()}</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="typ">ReactDOM</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(&lt;</span><span class="typ">App</span><span class="pln"> </span><span class="pun">/&gt;,</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'root'</span><span class="pun">))</span></pre>

<p>
	تضاف كل واجهة عرض على هيئة مكوّن خاص. وتُخزّن معلومات المكوّن في حالة التطبيق التي تحمل الاسم <code>page</code>. تخبرنا هذه المعلومات عن المكوّن الذي يمثل الواجهة التي ستعرض أسفل شريط القوائم.
</p>

<p>
	لكن هذا الأسلوب ليس الأسلوب الأمثل لتنفيذ ذلك. حيث يمكن أن نلاحظ من الصور التي عرضناها أن العنوان سيبقى نفسه للواجهات المختلفة. ومن المفضل أن تحمل كل واجهة عرض عنوانها الخاص، لتسهيل إنشاء اختصارات لها ضمن المتصفح على سبيل المثال. لن يعمل الزر "back" كما هو متوقع في التطبيق، أي أنه لن ينقلك إلى الواجهة السابقة بل إلى مكان مختلف كليًا. فإن توسع التطبيق وهذا ما نريده، عند إنشاء واجهات منفصلة لكل مستخدم أو ملاحظة فسيغدو هذا الأسلوب الذي اتبعناه في التوجه، والذي يدير آلية التنقل في التطبيق معقدًا بشكل كبير.
</p>

<p>
	لحسن الحظ تؤمن لنا المكتبة <a data-ss1615734954="1" href="https://github.com/ReactTraining/react-router" rel="external nofollow">React router</a> حلًا ممتازًا لإدارة التنقل بين الواجهات في تطبيقات React.
</p>

<p>
	لنغيّر التطبيق السابق بحيث يستخدم React-router. إذًا علينا أولًا تثبيت المكتبة بتنفيذ الأمر:
</p>

<pre class="ipsCode">
npm install react-router-dom
</pre>

<p>
	تُفعَّل آلية التنقل التي تؤمنها المكتبة السابقة كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6684_10" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="typ">BrowserRouter</span><span class="pln"> as </span><span class="typ">Router</span><span class="pun">,</span><span class="pln">
  </span><span class="typ">Switch</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Route</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Link</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> from </span><span class="str">"react-router-dom"</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> padding </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">Router</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">Link</span><span class="pln"> style</span><span class="pun">={</span><span class="pln">padding</span><span class="pun">}</span><span class="pln"> to</span><span class="pun">=</span><span class="str">"/"</span><span class="pun">&gt;</span><span class="pln">home</span><span class="pun">&lt;/</span><span class="typ">Link</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">Link</span><span class="pln"> style</span><span class="pun">={</span><span class="pln">padding</span><span class="pun">}</span><span class="pln"> to</span><span class="pun">=</span><span class="str">"/notes"</span><span class="pun">&gt;</span><span class="pln">notes</span><span class="pun">&lt;/</span><span class="typ">Link</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">Link</span><span class="pln"> style</span><span class="pun">={</span><span class="pln">padding</span><span class="pun">}</span><span class="pln"> to</span><span class="pun">=</span><span class="str">"/users"</span><span class="pun">&gt;</span><span class="pln">users</span><span class="pun">&lt;/</span><span class="typ">Link</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">

      </span><span class="pun">&lt;</span><span class="typ">Switch</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">Route</span><span class="pln"> path</span><span class="pun">=</span><span class="str">"/notes"</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Notes</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="typ">Route</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">Route</span><span class="pln"> path</span><span class="pun">=</span><span class="str">"/users"</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Users</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="typ">Route</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">Route</span><span class="pln"> path</span><span class="pun">=</span><span class="str">"/"</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Home</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="typ">Route</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="typ">Switch</span><span class="pun">&gt;</span><span class="pln">

      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">i</span><span class="pun">&gt;</span><span class="typ">Note</span><span class="pln"> app</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Department</span><span class="pln"> of </span><span class="typ">Computer</span><span class="pln"> </span><span class="typ">Science</span><span class="pln"> </span><span class="lit">2020</span><span class="pun">&lt;/</span><span class="pln">i</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="typ">Router</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تستخدم آلية التنقل أو التصيير الشرطي للمكوّنات المسؤولة عن عرض الواجهات بناء على عنوانها الظاهر على المتصفح، بوضع هذه المكوّنات كأبناء للمكوّن <code>Router</code>، أي داخل المُعِّرف <code>&lt;Router&gt;</code>.
</p>

<p>
	لاحظ أنه على الرغم من أنّ اسم المكوّن <code>Router</code>، فإننا نتحدث في الواقع عن موجِّه المتصفح <a data-ss1615734954="1" href="https://reacttraining.com/react-router/web/api/BrowserRouter" rel="external nofollow">BrowserRouter</a> حيث غيرنا اسم الكائن عندما أدرجناه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6684_12" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="typ">BrowserRouter</span><span class="pln"> as </span><span class="typ">Router</span><span class="pun">,</span><span class="pln">  </span><span class="typ">Switch</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Route</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Link</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> from </span><span class="str">"react-router-dom"</span></pre>

<p>
	وفقًا <a data-ss1615734954="1" href="https://reacttraining.com/react-router/web/api/BrowserRouter" rel="external nofollow">لدليل استخدام</a> المكتبة:
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p>
		موجّه المتصفح هو موجّه يستخدم واجهة المحفوظات البرمجية المتوافقة مع HTML5 (الأحداث pushState وreplaceState وpopState) لتبقى واجهة المستخدم متزامنة مع العنوان.
	</p>
</blockquote>

<p>
	يحمّل المتصفح عادة صفحة جديدة عندما يتغير العنوان ضمن شريط العناوين. لكن سيمكننا مكوّن موجّه المتصفح <code>BrowserRouter</code> بالاستفادة من الواجهة البرمجية <a data-ss1615734954="1" href="https://academy.hsoub.com/programming/html/html5/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%AA%D8%A3%D8%B1%D9%8A%D8%AE-%D9%81%D9%8A-html5-r443/" rel="">HTML5 history <abbr title="Application Programming Interface | واجهة برمجية">API</abbr></a> من استخدام العنوان الموجود في شريط العناوين للتنقل الداخلي ضمن الواجهات التي يعرضها تطبيق React.فحتى لو تغيّر العنوان ضمن شريط عناوين المتصفح سيتم التلاعب بمحتوى الصفحة باستخدام شيفرة JavaScript ولن يحمّل المتصفح محتوًى جديدًا من الخادم.
</p>

<p>
	وسيكون استخدام أفعال التراجع أو التقدم وحفظ الاختصارات منطقيًا كأي صفحة ويب تقليدية.
</p>

<p>
	نعرّف داخل الموجّه روابط <code>link</code> لتعديل شريط العناوين بمساعدة المكوّن <a data-ss1615734954="1" href="https://reacttraining.com/react-router/web/api/Link" rel="external nofollow">Link</a>. تنشئ الشيفرة التالية على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6684_14" style="">
<span class="tag">&lt;Link</span><span class="pln"> </span><span class="atn">to</span><span class="pun">=</span><span class="atv">"/notes"</span><span class="tag">&gt;</span><span class="pln">notes</span><span class="tag">&lt;/Link&gt;</span></pre>

<p>
	رابطًا داخل التطبيق له النص "notes" يغيّر بالنقر عليه العنوان في شريط عناوين المتصفح إلى العنوان "notes/".
</p>

<p>
	تٌعرّف المكوِّنات التي يجري تصييرها وفقًا للعنوان على المتصفح باستخدام المكوّن <a data-ss1615734954="1" href="https://reacttraining.com/react-router/web/api/Route" rel="external nofollow">Route</a>. فوظيفة الشيفرة التالية على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6684_16" style="">
<span class="tag">&lt;Route</span><span class="pln"> </span><span class="atn">path</span><span class="pun">=</span><span class="atv">"/notes"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;Notes</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
</span><span class="tag">&lt;/Route&gt;</span></pre>

<p>
	هو تصيير المكوّن <code>Note</code> إن كان العنوان المحدد في المتصفح هو "notes/". سنغلف المكونات التي ستُصيّر بناء على عنوان المتصفح داخل المكوّن <a data-ss1615734954="1" href="https://reacttraining.com/react-router/web/api/Switch" rel="external nofollow">Switch</a>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6684_18" style="">
<span class="tag">&lt;Switch&gt;</span><span class="pln">
  </span><span class="tag">&lt;Route</span><span class="pln"> </span><span class="atn">path</span><span class="pun">=</span><span class="atv">"/notes"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;Notes</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
  </span><span class="tag">&lt;/Route&gt;</span><span class="pln">
  </span><span class="tag">&lt;Route</span><span class="pln"> </span><span class="atn">path</span><span class="pun">=</span><span class="atv">"/users"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;Users</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
  </span><span class="tag">&lt;/Route&gt;</span><span class="pln">
  </span><span class="tag">&lt;Route</span><span class="pln"> </span><span class="atn">path</span><span class="pun">=</span><span class="atv">"/"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;Home</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
  </span><span class="tag">&lt;/Route&gt;</span><span class="pln">
</span><span class="tag">&lt;/Switch&gt;</span></pre>

<p>
	يصير المكوّن <code>switch</code> أول مكوّن داخله يتطابق مساره مع العنوان الموجود ضمن شريط عناوين المتصفح.
</p>

<p>
	وانتبه إلى أهمية ترتيب المكوّنات. فإن أردنا وضع المكوّن <code>Home</code> ذو المسار<code>"/"=path</code> أولًا، فلن يصير أي مكوّن آخر لأن المسار "/" غير موجود أصلًا فهو بداية كل المسارات:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6684_20" style="">
<span class="tag">&lt;Switch&gt;</span><span class="pln">
  </span><span class="tag">&lt;Route</span><span class="pln"> </span><span class="atn">path</span><span class="pun">=</span><span class="atv">"/"</span><span class="tag">&gt;</span><span class="pln">
  	</span><span class="tag">&lt;Home</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
  </span><span class="tag">&lt;/Route&gt;</span><span class="pln">  
  </span><span class="tag">&lt;Route</span><span class="pln"> </span><span class="atn">path</span><span class="pun">=</span><span class="atv">"/notes"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;Notes</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
  </span><span class="tag">&lt;/Route&gt;</span><span class="pln">
  // ...
</span><span class="tag">&lt;/Switch&gt;</span></pre>

<h2>
	إسناد معاملات إلى الموجه
</h2>

<p>
	لنتفحص النسخة المعدّلة من المثال السابق. يمكنك أن تجد الشيفرة الكاملة للمثال على <a data-ss1615734954="1" href="https://github.com/fullstack-hy2020/misc/blob/master/router-app-v1.js" rel="external nofollow">Github</a>.
</p>

<p>
	يعرض التطبيق الآن خمس واجهات مختلفة يتحكم الموجّه بآلية عرضها. فبالإضافة إلى المكونات <code>Home</code> و<code>User</code> و<code>Notes</code>من المثال السابق سنجد المكوّن <code>Login</code> الذي يعرض واجهة لتسجيل الدخول والمكوّن <code>Note</code> الذي يعرض ملاحظة واحدة.
</p>

<p>
	لم نغير المكونين <code>Home</code> و<code>Users</code>، لكن <code>Notes</code> أعقد قليلًا لانها تصير قائمة الملاحظات التي تُمرّر إليها كخاصية بطريقة تمكننا من النقر على اسم كل ملاحظة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-ss1615734954="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/Notes_clickable_03.png.9938554ee2056286a0f63ffb032aeb60.png" data-fileid="59629" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="59629" data-unique="28wte1ry8" src="https://academy.hsoub.com/uploads/monthly_2021_03/Notes_clickable_03.png.9938554ee2056286a0f63ffb032aeb60.png" alt="Notes_clickable_03.png"></a>
</p>

<p>
	تأتي إمكانية النقر على اسم الملاحظة من المكوّن <code>Link</code>، فالنقر على اسم الملاحظة التي تحمل المعرّف 3 سيسبب وقوع الحدث الذي يغيّر العنوان في المتصفح إلى "notes/3":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6684_22" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Notes</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln">notes</span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="typ">Notes</span><span class="pun">&lt;/</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">li key</span><span class="pun">={</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Link</span><span class="pln"> to</span><span class="pun">={`/</span><span class="pln">notes</span><span class="pun">/</span><span class="pln">$</span><span class="pun">{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}`}&gt;{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">content</span><span class="pun">}&lt;/</span><span class="typ">Link</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">)}</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">)</span></pre>

<p>
	نعرّف العناوين ذات المعاملات في الموجّه ضمن المكوّن <code>App</code> كالتالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6684_24" style="">
<span class="tag">&lt;Router&gt;</span><span class="pln">
  </span><span class="tag">&lt;div&gt;</span><span class="pln">
    </span><span class="tag">&lt;div&gt;</span><span class="pln">
      </span><span class="tag">&lt;Link</span><span class="pln"> </span><span class="atn">style</span><span class="pun">={</span><span class="pln">padding</span><span class="pun">}</span><span class="pln"> </span><span class="atn">to</span><span class="pun">=</span><span class="atv">"/"</span><span class="tag">&gt;</span><span class="pln">home</span><span class="tag">&lt;/Link&gt;</span><span class="pln">
      </span><span class="tag">&lt;Link</span><span class="pln"> </span><span class="atn">style</span><span class="pun">={</span><span class="pln">padding</span><span class="pun">}</span><span class="pln"> </span><span class="atn">to</span><span class="pun">=</span><span class="atv">"/notes"</span><span class="tag">&gt;</span><span class="pln">notes</span><span class="tag">&lt;/Link&gt;</span><span class="pln">
      </span><span class="tag">&lt;Link</span><span class="pln"> </span><span class="atn">style</span><span class="pun">={</span><span class="pln">padding</span><span class="pun">}</span><span class="pln"> </span><span class="atn">to</span><span class="pun">=</span><span class="atv">"/users"</span><span class="tag">&gt;</span><span class="pln">users</span><span class="tag">&lt;/Link&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">

    </span><span class="tag">&lt;Switch&gt;</span><span class="pln">
      </span><span class="tag">&lt;Route</span><span class="pln"> </span><span class="atn">path</span><span class="pun">=</span><span class="atv">"/notes/:id"</span><span class="tag">&gt;</span><span class="pln">        
          </span><span class="tag">&lt;Note</span><span class="pln"> </span><span class="atn">notes</span><span class="pun">=</span><span class="atv">{notes}</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">      
     </span><span class="tag">&lt;/Route&gt;</span><span class="pln">      
      </span><span class="tag">&lt;Route</span><span class="pln"> </span><span class="atn">path</span><span class="pun">=</span><span class="atv">"/notes"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;Notes</span><span class="pln"> </span><span class="atn">notes</span><span class="pun">=</span><span class="atv">{notes}</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
      </span><span class="tag">&lt;/Route&gt;</span><span class="pln">
      </span><span class="tag">&lt;Route</span><span class="pln"> </span><span class="atn">path</span><span class="pun">=</span><span class="atv">"/"</span><span class="tag">&gt;</span><span class="pln">
        </span><span class="tag">&lt;Home</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
      </span><span class="tag">&lt;/Route&gt;</span><span class="pln">
    </span><span class="tag">&lt;/Switch&gt;</span><span class="pln">

</span><span class="tag">&lt;/Router&gt;</span></pre>

<p>
	نعرّف الموجّه الذي يصير ملاحظة محددة " بتنسيق express" بتعليم المعامل بالوسم "id:":
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6684_26" style="">
<span class="tag">&lt;Route</span><span class="pln"> </span><span class="atn">path</span><span class="pun">=</span><span class="atv">"/notes/:id"</span><span class="tag">&gt;</span></pre>

<p>
	فعندما ينتقل المتصفح إلى عنوان الملاحظة المحددة، "notes/3/" على سبيل المثال، يُصّير المكوّن <code>Note</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6684_28" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
  useParams</span><span class="pun">}</span><span class="pln"> from </span><span class="str">"react-router-dom"</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Note</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> notes </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> id </span><span class="pun">=</span><span class="pln"> useParams</span><span class="pun">().</span><span class="pln">id  
  </span><span class="kwd">const</span><span class="pln"> note </span><span class="pun">=</span><span class="pln"> notes</span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="pln">n </span><span class="pun">=&gt;</span><span class="pln"> n</span><span class="pun">.</span><span class="pln">id </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Number</span><span class="pun">(</span><span class="pln">id</span><span class="pun">))</span><span class="pln"> 
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h2</span><span class="pun">&gt;{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">content</span><span class="pun">}&lt;/</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">user</span><span class="pun">}&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;&lt;</span><span class="pln">strong</span><span class="pun">&gt;{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">important </span><span class="pun">?</span><span class="pln"> </span><span class="str">'important'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">''</span><span class="pun">}&lt;</span><span class="str">/strong&gt;&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يتلقى المكوّن <code>Notes</code> كل الملاحظات ضمن الخاصيّة <code>notes</code>، ويمكنه بعدها الوصول إلى معامل العنوان (معرّف الملاحظة التي ستُعرض) باستخدام الدالة <a data-ss1615734954="1" href="https://reacttraining.com/react-router/web/api/Hooks/useparams" rel="external nofollow">useParams</a> العائدة للمكتبة react-router.
</p>

<h2>
	استخدام الدالة useHistory
</h2>

<p>
	أضفنا أيضًا طريقة بسيطة لتسجيل الدخول في تطبيقنا. فإن سجّل المستخدم دخوله ستُخزّن معلومات تسجيل الدخول في الحقل <code>user</code> من حالة المكوّن <code>App</code>.
</p>

<p>
	يُصيّر خيار الانتقال إلى واجهة تسجيل الدخول شرطيًا في القائمة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6684_30" style="">
<span class="tag">&lt;Router&gt;</span><span class="pln">
  </span><span class="tag">&lt;div&gt;</span><span class="pln">
    </span><span class="tag">&lt;Link</span><span class="pln"> </span><span class="atn">style</span><span class="pun">={</span><span class="pln">padding</span><span class="pun">}</span><span class="pln"> </span><span class="atn">to</span><span class="pun">=</span><span class="atv">"/"</span><span class="tag">&gt;</span><span class="pln">home</span><span class="tag">&lt;/Link&gt;</span><span class="pln">
    </span><span class="tag">&lt;Link</span><span class="pln"> </span><span class="atn">style</span><span class="pun">={</span><span class="pln">padding</span><span class="pun">}</span><span class="pln"> </span><span class="atn">to</span><span class="pun">=</span><span class="atv">"/notes"</span><span class="tag">&gt;</span><span class="pln">notes</span><span class="tag">&lt;/Link&gt;</span><span class="pln">
    </span><span class="tag">&lt;Link</span><span class="pln"> </span><span class="atn">style</span><span class="pun">={</span><span class="pln">padding</span><span class="pun">}</span><span class="pln"> </span><span class="atn">to</span><span class="pun">=</span><span class="atv">"/users"</span><span class="tag">&gt;</span><span class="pln">users</span><span class="tag">&lt;/Link&gt;</span><span class="pln">
    {user
      ? </span><span class="tag">&lt;em&gt;</span><span class="pln">{user} logged in</span><span class="tag">&lt;/em&gt;</span><span class="pln">
      : </span><span class="tag">&lt;Link</span><span class="pln"> </span><span class="atn">style</span><span class="pun">={</span><span class="pln">padding</span><span class="pun">}</span><span class="pln"> </span><span class="atn">to</span><span class="pun">=</span><span class="atv">"/login"</span><span class="tag">&gt;</span><span class="pln">login</span><span class="tag">&lt;/Link&gt;</span><span class="pln">
    }
  </span><span class="tag">&lt;/div&gt;</span><span class="pln">

  // ...
</span><span class="tag">&lt;/Router&gt;</span></pre>

<p>
	فلو سجلّ المستخدم دخوله للتو، فسيُظهر التطبيق اسم المستخدم بدلًا من الانتقال إلى واجهة تسجيل الدخول:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-ss1615734954="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/log_in_view_04.png.ad752ea73c1372e4b6cc11caaa4215a2.png" data-fileid="59625" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="59625" data-unique="6snozkysf" src="https://academy.hsoub.com/uploads/monthly_2021_03/log_in_view_04.png.ad752ea73c1372e4b6cc11caaa4215a2.png" alt="log_in_view_04.png"></a>
</p>

<p>
	تعطي الشيفرة التالية وظيفة تسجيل الدخول لتطبيقنا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6684_32" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
  useHistory</span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react-router-dom'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Login</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> history </span><span class="pun">=</span><span class="pln"> useHistory</span><span class="pun">()</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> onSubmit </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">
    props</span><span class="pun">.</span><span class="pln">onLogin</span><span class="pun">(</span><span class="str">'mluukkai'</span><span class="pun">)</span><span class="pln">
    history</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="str">'/'</span><span class="pun">)</span><span class="pln">  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">login</span><span class="pun">&lt;/</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">form onSubmit</span><span class="pun">={</span><span class="pln">onSubmit</span><span class="pun">}&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
          username</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">input </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
          password</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">input type</span><span class="pun">=</span><span class="str">'password'</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">button type</span><span class="pun">=</span><span class="str">"submit"</span><span class="pun">&gt;</span><span class="pln">login</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	إن ما يلفت الانتباه في هذا المكوّن هو استخدامه الدالة <a data-ss1615734954="1" href="https://reacttraining.com/react-router/web/api/Hooks/usehistory" rel="external nofollow">useHistory</a>. حيث يمكن للمكوّن الولوج إلى كائن محفوظات <a data-ss1615734954="1" href="https://reacttraining.com/react-router/web/api/history" rel="external nofollow">history</a> باستخدام تلك الدالة. ويستخدم كائن المحفوظات لتغيير عنوان المتصفح برمجيًا.
</p>

<p>
	فعند تسجيل الدخول، يُستدعى التابع <code>('/')history.push</code> العائد لكائن المحفوظات والذي يسبب تغييرًا في عنوان المتصفح إلى "/" ويصيِّر بعدها التطبيق المكوّن <code>Home</code>.
</p>

<p>
	تمثل كلا الدالتين <a data-ss1615734954="1" href="https://reacttraining.com/react-router/web/api/Hooks/useparams" rel="external nofollow">useParams</a> و<a data-ss1615734954="1" href="https://reacttraining.com/react-router/web/api/Hooks/usehistory" rel="external nofollow">useHistory</a> دوال خطافات تمامًا كالدوال <code>useState</code> و<code>useEffect</code> والتي استخدمناها عدة مرات سابقًا. وكما أسلفنا في القسم 1 فهنالك الكثير من <a data-ss1615734954="1" href="https://fullstackopen.com/en/part1/a_more_complex_state_debugging_react_apps/#rules-of-hooks" rel="external nofollow">القواعد</a> لاستخدام دوال الخطافات. وقد هيئت تطبيقات Creat-react-app لتنبيهك إن أغفلت تلك القواعد، كاستدعاء دوال الخطافات من داخل العبارات الشرطية.
</p>

<h2>
	إعادة التوجيه
</h2>

<p>
	يبقى هناك تفصيل مهم يتعلق بالمسار <code>Users</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6684_34" style="">
<span class="tag">&lt;Route</span><span class="pln"> </span><span class="atn">path</span><span class="pun">=</span><span class="atv">"/users"</span><span class="pln"> </span><span class="atn">render</span><span class="pun">=</span><span class="atv">{()</span><span class="pln"> </span><span class="tag">=&gt;</span><span class="pln">
  user ? </span><span class="tag">&lt;Users</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln"> : </span><span class="tag">&lt;Redirect</span><span class="pln"> </span><span class="atn">to</span><span class="pun">=</span><span class="atv">"/login"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
} /&gt;</span></pre>

<p>
	إن لم يسجل المستخدم دخوله، فلن يصيّر المكوّن <code>Users</code>. وبدلًا من ذلك سيعاد توجيه المستخدم إلى واجهة تسجيل الدخول باستخدام المكوّن <code>Redirect</code>.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6684_36" style="">
<span class="tag">&lt;Redirect</span><span class="pln"> </span><span class="atn">to</span><span class="pun">=</span><span class="atv">"/login"</span><span class="pln"> </span><span class="tag">/&gt;</span></pre>

<p>
	من الأفضل في الواقع أن لا نظهر الروابط التي تحتاج إلى تسجيل الدخول في شريط التنقل إن لم يسجل المستخدم دخوله إلى التطبيق.
</p>

<p>
	تمثل الشيفرة التالية المكوّن <code>App</code> بشكله الكامل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6684_38" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">notes</span><span class="pun">,</span><span class="pln"> setNotes</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">([</span><span class="pln">
    </span><span class="com">// ...</span><span class="pln">
  </span><span class="pun">])</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">user</span><span class="pun">,</span><span class="pln"> setUser</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="kwd">null</span><span class="pun">)</span><span class="pln"> 

  </span><span class="kwd">const</span><span class="pln"> login </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">user</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    setUser</span><span class="pun">(</span><span class="pln">user</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> padding </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Router</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Link</span><span class="pln"> style</span><span class="pun">={</span><span class="pln">padding</span><span class="pun">}</span><span class="pln"> to</span><span class="pun">=</span><span class="str">"/"</span><span class="pun">&gt;</span><span class="pln">home</span><span class="pun">&lt;/</span><span class="typ">Link</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Link</span><span class="pln"> style</span><span class="pun">={</span><span class="pln">padding</span><span class="pun">}</span><span class="pln"> to</span><span class="pun">=</span><span class="str">"/notes"</span><span class="pun">&gt;</span><span class="pln">notes</span><span class="pun">&lt;/</span><span class="typ">Link</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Link</span><span class="pln"> style</span><span class="pun">={</span><span class="pln">padding</span><span class="pun">}</span><span class="pln"> to</span><span class="pun">=</span><span class="str">"/users"</span><span class="pun">&gt;</span><span class="pln">users</span><span class="pun">&lt;/</span><span class="typ">Link</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">{</span><span class="pln">user
            </span><span class="pun">?</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">em</span><span class="pun">&gt;{</span><span class="pln">user</span><span class="pun">}</span><span class="pln"> logged in</span><span class="pun">&lt;/</span><span class="pln">em</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">:</span><span class="pln"> </span><span class="pun">&lt;</span><span class="typ">Link</span><span class="pln"> style</span><span class="pun">={</span><span class="pln">padding</span><span class="pun">}</span><span class="pln"> to</span><span class="pun">=</span><span class="str">"/login"</span><span class="pun">&gt;</span><span class="pln">login</span><span class="pun">&lt;/</span><span class="typ">Link</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">

        </span><span class="pun">&lt;</span><span class="typ">Switch</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Route</span><span class="pln"> path</span><span class="pun">=</span><span class="str">"/notes/:id"</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="typ">Note</span><span class="pln"> notes</span><span class="pun">={</span><span class="pln">notes</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
          </span><span class="pun">&lt;/</span><span class="typ">Route</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Route</span><span class="pln"> path</span><span class="pun">=</span><span class="str">"/notes"</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="typ">Notes</span><span class="pln"> notes</span><span class="pun">={</span><span class="pln">notes</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
          </span><span class="pun">&lt;/</span><span class="typ">Route</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Route</span><span class="pln"> path</span><span class="pun">=</span><span class="str">"/users"</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">{</span><span class="pln">user </span><span class="pun">?</span><span class="pln"> </span><span class="pun">&lt;</span><span class="typ">Users</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="pun">&lt;</span><span class="typ">Redirect</span><span class="pln"> to</span><span class="pun">=</span><span class="str">"/login"</span><span class="pln"> </span><span class="pun">/&gt;}</span><span class="pln">
          </span><span class="pun">&lt;/</span><span class="typ">Route</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Route</span><span class="pln"> path</span><span class="pun">=</span><span class="str">"/login"</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="typ">Login</span><span class="pln"> onLogin</span><span class="pun">={</span><span class="pln">login</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
          </span><span class="pun">&lt;/</span><span class="typ">Route</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Route</span><span class="pln"> path</span><span class="pun">=</span><span class="str">"/"</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="typ">Home</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
          </span><span class="pun">&lt;/</span><span class="typ">Route</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="typ">Switch</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="typ">Router</span><span class="pun">&gt;</span><span class="pln">      
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">br </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">em</span><span class="pun">&gt;</span><span class="typ">Note</span><span class="pln"> app</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Department</span><span class="pln"> of </span><span class="typ">Computer</span><span class="pln"> </span><span class="typ">Science</span><span class="pln"> </span><span class="lit">2020</span><span class="pun">&lt;/</span><span class="pln">em</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	نعرّف في الشيفرة السابقة مكوّنًا شائع الاستخدام في تطبيقات الويب الحديثة ويدعى <code>footer</code> والذي يعرّف الجزء السفلي من شاشة عرض التطبيق خارج نطاق المكوّن <code>Router</code>، وبالتالي سيظهر دائمًا بغض النظر عن المكوّن الذي سيُعرض.
</p>

<h2>
	مرور آخر على إسناد المعاملات إلى الموجه
</h2>

<p>
	لاتزال هناك ثغرة في تطبيقنا. حيث يتلقى المكوّن <code>Note</code> كل الملاحظات على الرغم من أنه سيعرض الملاحظة التي يتطابق معرّفها مع معامل العنوان:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6684_40" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Note</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> notes </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
  </span><span class="kwd">const</span><span class="pln"> id </span><span class="pun">=</span><span class="pln"> useParams</span><span class="pun">().</span><span class="pln">id
  </span><span class="kwd">const</span><span class="pln"> note </span><span class="pun">=</span><span class="pln"> notes</span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="pln">n </span><span class="pun">=&gt;</span><span class="pln"> n</span><span class="pun">.</span><span class="pln">id </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Number</span><span class="pun">(</span><span class="pln">id</span><span class="pun">))</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	هل يمكن أن تعدّل التطبيق لكي يتلقى المكون <code>Note</code> المكوّن الذي سيُعرض فقط؟
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6684_42" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Note</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> note </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h2</span><span class="pun">&gt;{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">content</span><span class="pun">}&lt;/</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">user</span><span class="pun">}&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;&lt;</span><span class="pln">strong</span><span class="pun">&gt;{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">important </span><span class="pun">?</span><span class="pln"> </span><span class="str">'important'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">''</span><span class="pun">}&lt;</span><span class="str">/strong&gt;&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تعتمد إحدى الطرق المتبعة في تنفيذ ذلك على استخدام الخطاف <a data-ss1615734954="1" href="https://reacttraining.com/react-router/web/api/Hooks/useroutematch" rel="external nofollow">useRouteMatch</a> لتحديد معرّف الملاحظة التي ستُعرض ضمن المكوّن <code>App</code>.
</p>

<p>
	من غير الممكن أن نستخدم الخطاف <code>useRouteMatch</code> في المكوّن الذي يعرّف الشيفرة المسؤولة عن التنقل. لننقل إذًا المكوّن <code>Router</code> خارج المكوّن <code>App</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6684_44" style="">
<span class="typ">ReactDOM</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="typ">Router</span><span class="pun">&gt;</span><span class="pln">
  	</span><span class="pun">&lt;</span><span class="typ">App</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="typ">Router</span><span class="pun">&gt;,</span><span class="pln">
  document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'root'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">)</span></pre>

<p>
	سيصبح المكون <code>App</code> كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6684_46" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
  useRouteMatch</span><span class="pun">}</span><span class="pln"> from </span><span class="str">"react-router-dom"</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> match </span><span class="pun">=</span><span class="pln"> useRouteMatch</span><span class="pun">(</span><span class="str">'/notes/:id'</span><span class="pun">)</span><span class="pln">  
  </span><span class="kwd">const</span><span class="pln"> note </span><span class="pun">=</span><span class="pln"> match     
  </span><span class="pun">?</span><span class="pln"> notes</span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> note</span><span class="pun">.</span><span class="pln">id </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Number</span><span class="pun">(</span><span class="pln">match</span><span class="pun">.</span><span class="pln">params</span><span class="pun">.</span><span class="pln">id</span><span class="pun">))</span><span class="pln">    
  </span><span class="pun">:</span><span class="pln"> </span><span class="kwd">null</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">Link</span><span class="pln"> style</span><span class="pun">={</span><span class="pln">padding</span><span class="pun">}</span><span class="pln"> to</span><span class="pun">=</span><span class="str">"/"</span><span class="pun">&gt;</span><span class="pln">home</span><span class="pun">&lt;/</span><span class="typ">Link</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="com">// ...</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">

      </span><span class="pun">&lt;</span><span class="typ">Switch</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">Route</span><span class="pln"> path</span><span class="pun">=</span><span class="str">"/notes/:id"</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Note</span><span class="pln"> note</span><span class="pun">={</span><span class="pln">note</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">        
              </span><span class="pun">&lt;/</span><span class="typ">Route</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">Route</span><span class="pln"> path</span><span class="pun">=</span><span class="str">"/notes"</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Notes</span><span class="pln"> notes</span><span class="pun">={</span><span class="pln">notes</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="typ">Route</span><span class="pun">&gt;</span><span class="pln">
         </span><span class="com">// ...</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="typ">Switch</span><span class="pun">&gt;</span><span class="pln">

      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">em</span><span class="pun">&gt;</span><span class="typ">Note</span><span class="pln"> app</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Department</span><span class="pln"> of </span><span class="typ">Computer</span><span class="pln"> </span><span class="typ">Science</span><span class="pln"> </span><span class="lit">2020</span><span class="pun">&lt;/</span><span class="pln">em</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">    </span></pre>

<p>
	في كل مرة ستغير فيها العنوان على المتصفح سيجري تنفيذ الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6684_48" style="">
<span class="kwd">const</span><span class="pln"> match </span><span class="pun">=</span><span class="pln"> useRouteMatch</span><span class="pun">(</span><span class="str">'/notes/:id'</span><span class="pun">)</span></pre>

<p>
	إن تطابق العنوان مع القيمة "notes/:id/"، فسيُسند إلى متغير التطابق كائن يمكنه الولوج إلى القسم الذي يحوي المعامل من مسار العنوان وهو معرّف الملاحظة التي ستُعرض، وبالتالي يمكن إحضار الملاحظة المطلوبة وعرضها.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6684_50" style="">
<span class="kwd">const</span><span class="pln"> note </span><span class="pun">=</span><span class="pln"> match 
  </span><span class="pun">?</span><span class="pln"> notes</span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> note</span><span class="pun">.</span><span class="pln">id </span><span class="pun">===</span><span class="pln"> </span><span class="typ">Number</span><span class="pun">(</span><span class="pln">match</span><span class="pun">.</span><span class="pln">params</span><span class="pun">.</span><span class="pln">id</span><span class="pun">))</span><span class="pln">
  </span><span class="pun">:</span><span class="pln"> </span><span class="kwd">null</span></pre>

<p>
	ستجد الشيفرة كاملة على <a data-ss1615734954="1" href="https://github.com/fullstack-hy2020/misc/blob/master/router-app-v2.js" rel="external nofollow">GitHub</a>.
</p>

<h2>
	التمارين 7.1 - 7.3
</h2>

<p>
	سنعود إلى العمل في تطبيق الطرائف. استخدم نسخة التطبيق التي لا تعتمد على Redux والموجودة على <a data-ss1615734954="1" href="https://github.com/fullstack-hy2020/routed-anecdotes" rel="external nofollow">GitHub</a> كنقطة انطلاق للتمارين.
</p>

<p>
	إن نسخت الشيفرة ووضعتها في مستودع git موجود أصلًا، لاتنس حذف ملف تهيئة git لنسختك من التطبيق:
</p>

<h3>
	Exercises 7.1.-7.3.
</h3>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6684_52" style="">
<span class="pln">cd routed</span><span class="pun">-</span><span class="pln">anecdotes   </span><span class="com">// توجه أوّلًا إلى المستودع الذي يحوي نسختك من التطبيق</span><span class="pln">
rm </span><span class="pun">-</span><span class="pln">rf </span><span class="pun">.</span><span class="pln">git</span></pre>

<p>
	شغّل التطبيق بالطريقة الاعتيادية، لكن عليك أوّلًا تثبيت الاعتماديات اللازمة:
</p>

<pre class="ipsCode">
npm install
npm start
</pre>

<h3>
	7.1 تطبيق الطرائف بشريط للتنقل: الخطوة 1
</h3>

<p>
	أضف موجّه React إلى التطبيق بحيث يمكن تغيير الواجهة المعروضة عند النقر على الروابط في المكوّن <code>Menu</code>. أظهر قائمة الطرائف عند الوصول إلى جذر التطبيق (الموقع الذي يحمل المسار "/")
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-ss1615734954="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/Anecdote_nav_menu_05.png.778a87decaba370d84c517851120e15e.png" data-fileid="59622" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="59622" data-unique="pken99wgo" src="https://academy.hsoub.com/uploads/monthly_2021_03/Anecdote_nav_menu_05.png.778a87decaba370d84c517851120e15e.png" alt="Anecdote_nav_menu_05.png"></a>
</p>

<p>
	ينبغي أن يظهر المكوّن <code>Footer</code> بشكل دائم في أسفل الشاشة.
</p>

<p>
	كما ينبغي إنشاء الطرفة الجديدة في مسار خاص، ضمن المسار "create" على سبيل المثال:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-ss1615734954="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/New_anecdote_06.png.6356eab5567dc731a6af2d06bb977d07.png" data-fileid="59627" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="59627" data-unique="8knilotgl" src="https://academy.hsoub.com/uploads/monthly_2021_03/New_anecdote_06.png.6356eab5567dc731a6af2d06bb977d07.png" alt="New_anecdote_06.png"></a>
</p>

<h3>
	7.2 تطبيق الطرائف بشريط للتنقل: الخطوة 2
</h3>

<p>
	أضف إمكانية عرض طرفة واحدة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-ss1615734954="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/show_single_aneddote_07.png.d88f689cda3d3a5a9d1f36f5a581148a.png" data-fileid="59630" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="59630" data-unique="vtu3r87jv" src="https://academy.hsoub.com/uploads/monthly_2021_03/show_single_aneddote_07.png.d88f689cda3d3a5a9d1f36f5a581148a.png" alt="show_single_aneddote_07.png"></a>
</p>

<p>
	انتقل إلى الصفحة التي تعرض طرفة واحدة بالنقر على اسم الطرفة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-ss1615734954="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/navigate_by_click_08.png.bcf2043eef9f179029ebc653bfe2e777.png" data-fileid="59626" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="59626" data-unique="4pn728uuh" src="https://academy.hsoub.com/uploads/monthly_2021_03/navigate_by_click_08.png.bcf2043eef9f179029ebc653bfe2e777.png" alt="navigate_by_click_08.png"></a>
</p>

<h3>
	7.3 تطبيق الطرائف بشريط للتنقل: الخطوة 3
</h3>

<p>
	ستغدو الوظيفة الافتراضية لنموذج إنشاء طرفة جديدة مربكة قليلًا لأن شيئًا لن يحدث عند إنشاء طرفة جديدة باستخدام النموذج.
</p>

<p>
	حسّن الأمر بحيث ينتقل التطبيق تلقائيًا إلى إظهار كل الطرائف عند إنشاء الطرفة الجديدة، ويظهر تنبيه للمستخدم مدته عشر ثوان، لإبلاغه بإضافة طرفة جديدة
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-ss1615734954="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/new_anecdote_09.png.3f3b05e5b9be6029481e4d2aa1bb6d2c.png" data-fileid="59628" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="59628" data-unique="o6h6qsg1x" src="https://academy.hsoub.com/uploads/monthly_2021_03/new_anecdote_09.png.3f3b05e5b9be6029481e4d2aa1bb6d2c.png" alt="new_anecdote_09.png"></a>
</p>

<p>
	ترجمة -وبتصرف- للفصل <a data-ss1615734954="1" href="https://fullstackopen.com/en/part7/react_router" rel="external nofollow">React-Router</a> من سلسلة <a data-ss1615734954="1" href="https://fullstackopen.com/en/" rel="external nofollow">Deep Dive Into Modern Web Development</a>
</p>
]]></description><guid isPermaLink="false">1166</guid><pubDate>Thu, 25 Mar 2021 13:04:02 +0000</pubDate></item><item><title>&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x627;&#x644;&#x62F;&#x627;&#x644;&#x629; connect &#x641;&#x64A; Redux &#x641;&#x64A; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; React</title><link>https://academy.hsoub.com/programming/javascript/react/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D8%AF%D8%A7%D9%84%D8%A9-connect-%D9%81%D9%8A-redux-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-react-r1165/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_03/604e25464f5a7_--connect--Redux---React.png.0c3f96ff577effc42638be87fedb5f4e.png" /></p>

<p>
	لقد استخدمنا حتى اللحظة مخزن Redux بمساعدة <a data-ss1615734074="1" href="https://react-redux.js.org/api/hooks" rel="external nofollow">واجهة خطافات</a> أمنتها المكتبة react-redux. وقد استخدمنا بالتحديد الدالتين <a data-ss1615734074="1" href="https://react-redux.js.org/api/hooks#useselector" rel="external nofollow">useSelector</a> و<a data-ss1615734074="1" href="https://react-redux.js.org/api/hooks#usedispatch" rel="external nofollow">useDispatch</a>.
</p>

<p>
	ولنكمل هذا القسم علينا الاطلاع على طريقة أقدم وأكثر تعقيدًا لاستخدام Redux، وهي استخدام الدالة <a data-ss1615734074="1" href="https://github.com/reduxjs/react-redux/blob/master/docs/api/connect.md" rel="external nofollow">connect</a> التي تؤمنها المكتبة Redux.
</p>

<p>
	عليك قطعًا استخدام واجهة الخطافات البرمجية عندما تنشئ تطبيقات جديدة، لكن معرفة طريقة عمل <code>connect</code> أمر ضروري عند صيانة مشاريع Redux أقدم.
</p>

<h2>
	استخدام الدالة connect لمشاركة مخزن Redux بين المكوِّنات
</h2>

<p>
	لنعدّل المكوِّن <code>Notes</code> بحيث يستخدم الدالة <code>connect</code> بدلًا من واجهة الخطافات البرمجية (بدلًا من استخدام الدالتين <a data-ss1615734074="1" href="https://react-redux.js.org/api/hooks#useselector" rel="external nofollow">useSelector</a> و<a data-ss1615734074="1" href="https://react-redux.js.org/api/hooks#usedispatch" rel="external nofollow">useDispatch</a>).علينا تعديل الإجزاء التالية من المكوِّن:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3032_8" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> useDispatch</span><span class="pun">,</span><span class="pln"> useSelector </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react-redux'</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> toggleImportanceOf </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'../reducers/noteReducer'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Notes</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> dispatch </span><span class="pun">=</span><span class="pln"> useDispatch</span><span class="pun">()</span><span class="pln">   
  </span><span class="kwd">const</span><span class="pln"> notes </span><span class="pun">=</span><span class="pln"> useSelector</span><span class="pun">(({</span><span class="pln">filter</span><span class="pun">,</span><span class="pln"> notes</span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">    
      </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> filter </span><span class="pun">===</span><span class="pln"> </span><span class="str">'ALL'</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">      
          </span><span class="kwd">return</span><span class="pln"> notes    
      </span><span class="pun">}</span><span class="pln">    
      </span><span class="kwd">return</span><span class="pln"> filter  </span><span class="pun">===</span><span class="pln"> </span><span class="str">'IMPORTANT'</span><span class="pln">       
          </span><span class="pun">?</span><span class="pln"> notes</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> note</span><span class="pun">.</span><span class="pln">important</span><span class="pun">)</span><span class="pln">      
          </span><span class="pun">:</span><span class="pln"> notes</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">!</span><span class="pln">note</span><span class="pun">.</span><span class="pln">important</span><span class="pun">)</span><span class="pln">  
  </span><span class="pun">})</span><span class="pln">
  </span><span class="kwd">return</span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">Note</span><span class="pln">
          key</span><span class="pun">={</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}</span><span class="pln">
          note</span><span class="pun">={</span><span class="pln">note</span><span class="pun">}</span><span class="pln">
          handleClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> 
            dispatch</span><span class="pun">(</span><span class="pln">toggleImportanceOf</span><span class="pun">(</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">))</span><span class="pln">          
</span><span class="pun">}</span><span class="pln">
        </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">)}</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">Notes</span></pre>

<p>
	يمكن استخدام الدالة <code>connect</code> لتحويل مكونات React "النظامية" بحيث يتصل المكوِّن بحالة مخزن Redux عن طريق خصائصه. لنستخدم أولًا الدالة <code>connect</code> لتحويل المكوّن <code>Notes</code> إلى مكوّن متّصل (connected component):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3032_10" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> connect </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react-redux'</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> toggleImportanceOf </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'../reducers/noteReducer'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Notes</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">ConnectedNotes</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> connect</span><span class="pun">()(</span><span class="typ">Notes</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">ConnectedNotes</span></pre>

<p>
	تُصدِّر الوحدة المكوِّن المتصل والذي سيعمل حاليًا كالمكوّن النظامي السابق تمامًا. يحتاج المكوِّن إلى قائمة بالملاحظات وإلى قيمة المُرشِّح من مخزن Redux. تستقبل الدالة <code>connect</code> دالة أخرى تدعى <a data-ss1615734074="1" href="https://github.com/reduxjs/react-redux/blob/master/docs/api/connect.md#mapstatetoprops-state-ownprops--object" rel="external nofollow">mapStateToProps</a> كمعامل أول. حيث تُستخدم هذه الأخيرة في تعريف خصائص المكوِّن المتصل والتي تعتمد على حالة مخزن Redux. لو كتبنا الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3032_12" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Notes</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  
  </span><span class="kwd">const</span><span class="pln"> dispatch </span><span class="pun">=</span><span class="pln"> useDispatch</span><span class="pun">()</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> notesToShow </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">    
      </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> props</span><span class="pun">.</span><span class="pln">filter </span><span class="pun">===</span><span class="pln"> </span><span class="str">'ALL '</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">      
          </span><span class="kwd">return</span><span class="pln"> props</span><span class="pun">.</span><span class="pln">notes    
      </span><span class="pun">}</span><span class="pln">        
      </span><span class="kwd">return</span><span class="pln"> props</span><span class="pun">.</span><span class="pln">filter  </span><span class="pun">===</span><span class="pln"> </span><span class="str">'IMPORTANT'</span><span class="pln">       
          </span><span class="pun">?</span><span class="pln"> props</span><span class="pun">.</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> note</span><span class="pun">.</span><span class="pln">important</span><span class="pun">)</span><span class="pln">      
      </span><span class="pun">:</span><span class="pln">props</span><span class="pun">.</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">!</span><span class="pln">note</span><span class="pun">.</span><span class="pln">important</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">return</span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">notesToShow</span><span class="pun">().</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln">        
       </span><span class="pun">&lt;</span><span class="typ">Note</span><span class="pln">
          key</span><span class="pun">={</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}</span><span class="pln">
          note</span><span class="pun">={</span><span class="pln">note</span><span class="pun">}</span><span class="pln">
          handleClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> 
            dispatch</span><span class="pun">(</span><span class="pln">toggleImportanceOf</span><span class="pun">(</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">))</span><span class="pln">
          </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">)}</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> mapStateToProps </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    notes</span><span class="pun">:</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">notes</span><span class="pun">,</span><span class="pln">
    filter</span><span class="pun">:</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">ConnectedNotes</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> connect</span><span class="pun">(</span><span class="pln">mapStateToProps</span><span class="pun">)(</span><span class="typ">Notes</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">ConnectedNotes</span></pre>

<p>
	يمكن للمكون أن يلج حالة المخزن مباشرة من خلال الأمر<code>props.notes</code> والذي يعطينا قائمة الملاحظات. كما يمكن الوصول إلى قيمة المرشِّح من خلال الأمر <code>props.filter</code>. كما يمكن توضيح الحالة التي تنتج عن استخدام الدالة <code>connect</code> مع الدالة <code>mapStateToProps</code> التي عرفناها كما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-ss1615734074="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/connect_map_to_props_01.png.9b1cbc4c0f582ee80b329b1644cebf6a.png" data-fileid="59620" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="59620" data-unique="mzj9ao70k" src="https://academy.hsoub.com/uploads/monthly_2021_03/connect_map_to_props_01.png.9b1cbc4c0f582ee80b329b1644cebf6a.png" alt="connect_map_to_props_01.png"></a>
</p>

<p>
	ويمكن أيضًا للمكوِّن <code>Notes</code> أن يصل مباشرة إلى المخزن بالطريقة التي ذكرناها سابقًا لغرض التحري والتفتيش. لا يحتاج المكوّن <code>NoteList</code> عمليًا إلى أية معلومات حول المُرشِّح المختار، لذلك يمكن نقل منطق عملية الانتقاء إلى مكان آخر. وعلينا فقط تقديم الملاحظات المنتقاة بشكل صحيح للمكوّن من خلال الخاصية <code>note</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3032_14" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Notes</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  </span><span class="kwd">const</span><span class="pln"> dispatch </span><span class="pun">=</span><span class="pln"> useDispatch</span><span class="pun">()</span><span class="pln">

  </span><span class="kwd">return</span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">Note</span><span class="pln">
          key</span><span class="pun">={</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}</span><span class="pln">
          note</span><span class="pun">={</span><span class="pln">note</span><span class="pun">}</span><span class="pln">
          handleClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> 
            dispatch</span><span class="pun">(</span><span class="pln">toggleImportanceOf</span><span class="pun">(</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">))</span><span class="pln">
          </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">)}</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> mapStateToProps </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">filter </span><span class="pun">===</span><span class="pln"> </span><span class="str">'ALL'</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">    
        </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">      
            notes</span><span class="pun">:</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">notes    
        </span><span class="pun">}</span><span class="pln">  
    </span><span class="pun">}</span><span class="pln">  
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">    
        notes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">.</span><span class="pln">filter  </span><span class="pun">===</span><span class="pln"> </span><span class="str">'IMPORTANT'</span><span class="pln">       
                </span><span class="pun">?</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> note</span><span class="pun">.</span><span class="pln">important</span><span class="pun">)</span><span class="pln">      
                </span><span class="pun">:</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">!</span><span class="pln">note</span><span class="pun">.</span><span class="pln">important</span><span class="pun">)</span><span class="pln">    
               </span><span class="pun">)</span><span class="pln">  
    </span><span class="pun">}}</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">ConnectedNotes</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> connect</span><span class="pun">(</span><span class="pln">mapStateToProps</span><span class="pun">)(</span><span class="typ">Notes</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">ConnectedNotes</span><span class="pln">  </span></pre>

<h3>
	الدالة mapDispatchToProps
</h3>

<p>
	لقد تخلصنا الآن من الدالة <code>useSelector</code>، لكن المكوّن <code>Note</code> لايزال يستخدم الخطاف <code>useDispatch</code> ودالة الإيفاد التي تستخدمه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3032_16" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Notes</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> dispatch </span><span class="pun">=</span><span class="pln"> useDispatch</span><span class="pun">()</span><span class="pln">
  </span><span class="kwd">return</span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">Note</span><span class="pln">
          key</span><span class="pun">={</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}</span><span class="pln">
          note</span><span class="pun">={</span><span class="pln">note</span><span class="pun">}</span><span class="pln">
          handleClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> 
            dispatch</span><span class="pun">(</span><span class="pln">toggleImportanceOf</span><span class="pun">(</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">))</span><span class="pln">          
</span><span class="pun">}</span><span class="pln">
        </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">)}</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يستخدم المعامل الثاني للدالة <code>connect</code> لتعريف الدالة <a data-ss1615734074="1" href="https://github.com/reduxjs/react-redux/blob/master/docs/api/connect.md#mapdispatchtoprops-object--dispatch-ownprops--object" rel="external nofollow">mapDispatchToProps</a>، ويمثل هذا المعامل مجموعة من الدوال المولدة للأفعال، تُمرّر إلى الدالة <code>connect</code> كخاصية. لنجري التعديلات التالية على عملية الاتصال التي أنشأناها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3032_18" style="">
<span class="kwd">const</span><span class="pln"> mapStateToProps </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    notes</span><span class="pun">:</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">notes</span><span class="pun">,</span><span class="pln">
    filter</span><span class="pun">:</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> mapDispatchToProps </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  toggleImportanceOf</span><span class="pun">,}</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">ConnectedNotes</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> connect</span><span class="pun">(</span><span class="pln">
  mapStateToProps</span><span class="pun">,</span><span class="pln">
  mapDispatchToProps</span><span class="pun">)(</span><span class="typ">Notes</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">ConnectedNotes</span></pre>

<p>
	يستطيع المكوّن الآن إيفاد الفعل الذي يعّرفه مولد الأفعال <code>toggleImportanceOf</code> مباشرةً، عن طريق طلب الدالة من خلال خصائصها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3032_20" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Notes</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">Note</span><span class="pln">
          key</span><span class="pun">={</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}</span><span class="pln">
          note</span><span class="pun">={</span><span class="pln">note</span><span class="pun">}</span><span class="pln">
          handleClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> props</span><span class="pun">.</span><span class="pln">toggleImportanceOf</span><span class="pun">(</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">)}</span><span class="pln">
        </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">)}</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أي بدلًا من إيفاد الفعل بالطريقة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3032_22" style="">
<span class="pln">dispatch</span><span class="pun">(</span><span class="pln">toggleImportanceOf</span><span class="pun">(</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">))</span></pre>

<p>
	يمكننا ببساطة إنجاز ذلك باستخدام <code>connect</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3032_24" style="">
<span class="pln">props</span><span class="pun">.</span><span class="pln">toggleImportanceOf</span><span class="pun">(</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">)</span></pre>

<p>
	لا حاجة لطلب الدالة <code>dispatch</code> بشكل منفصل، طالما أنّ الدالة <code>connect</code> قد عدلت مولد الفعل <code>toggleImportanceOf</code> إلى الشكل الذي يحتوي <code>dispatch</code>.
</p>

<p>
	سيتطلب منك الأمر بعض الوقت لتقلب في ذهنك الطريقة التي تعمل بها الدالة <code>mapDispatchToProps</code>، وخاصة عندما سنلقي نظرة على طرق بديلة لاستخدامها لاحقًا في هذا الفصل.
</p>

<p>
	يمكن إظهار النتيجة التي سنحصل عليها باستخدام <code>connect</code> من خلال الشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-ss1615734074="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/visualize_connect_02.png.f285f3192ed0dc424830f9aca1b5b876.png" data-fileid="59621" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="59621" data-unique="q3ogap4qy" src="https://academy.hsoub.com/uploads/monthly_2021_03/visualize_connect_02.thumb.png.6e40d7ca4e6984afac7241f2f6894215.png" alt="visualize_connect_02.png"></a>
</p>

<p>
	وبالإضافة إلى قدرته على الولوج إلى حالة المخزن، يمكن للمكوِّن الإشارة إلى دالة يمكن أن تستخدم لإيفاد أفعال من النوع <code>TOGGLE_IMPORTANCE</code> من خلال الخاصية <code>toggleImportanceOf</code>.
</p>

<p>
	تمثل الشيفرة التالية المكوّن <code>Notes</code> وقد كُتب من جديد:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3032_26" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> connect </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react-redux'</span><span class="pln"> 
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> toggleImportanceOf </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'../reducers/noteReducer'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Notes</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">Note</span><span class="pln">
          key</span><span class="pun">={</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}</span><span class="pln">
          note</span><span class="pun">={</span><span class="pln">note</span><span class="pun">}</span><span class="pln">
          handleClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> props</span><span class="pun">.</span><span class="pln">toggleImportanceOf</span><span class="pun">(</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">)}</span><span class="pln">
        </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">)}</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> mapStateToProps </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">filter </span><span class="pun">===</span><span class="pln"> </span><span class="str">'ALL'</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      notes</span><span class="pun">:</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">notes
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    notes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">.</span><span class="pln">filter  </span><span class="pun">===</span><span class="pln"> </span><span class="str">'IMPORTANT'</span><span class="pln"> 
    </span><span class="pun">?</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> note</span><span class="pun">.</span><span class="pln">important</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">:</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">!</span><span class="pln">note</span><span class="pun">.</span><span class="pln">important</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> mapDispatchToProps </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  toggleImportanceOf
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> connect</span><span class="pun">(</span><span class="pln">
  mapStateToProps</span><span class="pun">,</span><span class="pln">
  mapDispatchToProps
</span><span class="pun">)(</span><span class="typ">Notes</span><span class="pun">)</span></pre>

<p>
	لنستخدم أيضًا الدالة <code>connect</code> لإنشاء ملاحظة جديدة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3032_28" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> connect </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react-redux'</span><span class="pln"> 
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> createNote </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'../reducers/noteReducer'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">NewNote</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  
  </span><span class="kwd">const</span><span class="pln"> addNote </span><span class="pun">=</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> content </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">note</span><span class="pun">.</span><span class="pln">value
    event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">note</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pln">
    props</span><span class="pun">.</span><span class="pln">createNote</span><span class="pun">(</span><span class="pln">content</span><span class="pun">)</span><span class="pln">  
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">form onSubmit</span><span class="pun">={</span><span class="pln">addNote</span><span class="pun">}&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">input name</span><span class="pun">=</span><span class="str">"note"</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button type</span><span class="pun">=</span><span class="str">"submit"</span><span class="pun">&gt;</span><span class="pln">add</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> connect</span><span class="pun">(</span><span class="pln">  </span><span class="kwd">null</span><span class="pun">,</span><span class="pln">   </span><span class="pun">{</span><span class="pln"> createNote </span><span class="pun">})(</span><span class="typ">NewNote</span><span class="pun">)</span></pre>

<p>
	وطالما أن المكوّن لن يحتاج الوصول إلى حالة المخزن، يمكننا أن نمرر ببساطة القيمة <code>null</code> كمعامل أول للدالة <code>connect</code>.
</p>

<p>
	يمكنك إيجاد الشيفرة الكاملة لتطبيقنا الحالي في الفرع part6-5 ضمن المستودع المخصص للتطبيق على <a data-ss1615734074="1" href="https://github.com/fullstack-hy2020/redux-notes/tree/part6-5" rel="external nofollow">GitHub</a>.
</p>

<h2>
	الإشارة المرجعية إلى مولدات الأفعال الممررة كخصائص
</h2>

<p>
	لنوجه اهتمامنا إلى الميزة الهامة التي يمتلكها المكوّن <code>NewNote</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3032_30" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> connect </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react-redux'</span><span class="pln"> 
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> createNote </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'../reducers/noteReducer'</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">NewNote</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> addNote </span><span class="pun">=</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> content </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">note</span><span class="pun">.</span><span class="pln">value
    event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">note</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pln">
    props</span><span class="pun">.</span><span class="pln">createNote</span><span class="pun">(</span><span class="pln">content</span><span class="pun">)</span><span class="pln">  
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">form onSubmit</span><span class="pun">={</span><span class="pln">addNote</span><span class="pun">}&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">input name</span><span class="pun">=</span><span class="str">"note"</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button type</span><span class="pun">=</span><span class="str">"submit"</span><span class="pun">&gt;</span><span class="pln">add</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> connect</span><span class="pun">(</span><span class="pln">
  </span><span class="kwd">null</span><span class="pun">,</span><span class="pln"> 
  </span><span class="pun">{</span><span class="pln"> createNote </span><span class="pun">})(</span><span class="typ">NewNote</span><span class="pun">)</span></pre>

<p>
	سيشعر المطورون حديثو المعرفة بالدالة <code>connect</code> بالحيرة أمام نسختي مولد الأفعال <code>createNote</code> في هذا المكوّن. يجب أن يُشار إلى دالة مولد الأفعال السابقة بالأمر <code>props.createNote</code> من خلال خصائص المكوّن، لأنها النسخة التي تنجز الإيفاد الذي تولده الدالة <code>connect</code> تلقائيًا. ونظرًا للطريقة التي يُدرج فيها مولد الفعل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3032_32" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> createNote </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'./../reducers/noteReducer'</span></pre>

<p>
	يمكن أن يُشار إلى مولد الفعل مباشرة بطلب الدالة <code>creatNote</code>. لكن لا تفعل ذلك، لأنها النسخة غير المعدلة من دالة مولد الفعل وبالتالي لا تمتلك آلية الإيفاد التلقائي.
</p>

<p>
	إن طبعنا الدالتين على الطرفية (لم نتطرق إلى هذه الحيلة في التنقيح بعد) كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3032_34" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">NewNote</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">createNote</span><span class="pun">)</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">props</span><span class="pun">.</span><span class="pln">createNote</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> addNote </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> content </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">note</span><span class="pun">.</span><span class="pln">value
    event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">note</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pln">
    props</span><span class="pun">.</span><span class="pln">createNote</span><span class="pun">(</span><span class="pln">content</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يمكن أن نجد الفرق بين الدالتين كما في الشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-ss1615734074="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/action_creator_virsions_03.png.2d8180ea2f24f3108c7db6fe55f2abe2.png" data-fileid="59619" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="59619" data-unique="ogwilfja6" src="https://academy.hsoub.com/uploads/monthly_2021_03/action_creator_virsions_03.png.2d8180ea2f24f3108c7db6fe55f2abe2.png" alt="action_creator_virsions_03.png"></a>
</p>

<p>
	حيث تظهر الدالة الأولى بأنها دالة مولد فعل نظامية، بينما ستحتوي الدالة الثانية آلية إيفاد إلى المخزن، أضافتها الدالة <code>connect</code>. تمثل الدالة <code>connect</code> أداة غاية في الأهمية بالرغم من أنها تبدو صعبة الفهم في البداية، نظرًا لمستوى التجريد العالي الذي تقدمه.
</p>

<h2>
	طرائق أخرى لاستخدام الدالة mapDispatchToProps
</h2>

<p>
	لقد عرفنا دالة إيفاد الأفعال من خلال المكوّن المتصل <code>NewNote</code> على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3032_36" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">NewNote</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> connect</span><span class="pun">(</span><span class="pln">
  </span><span class="kwd">null</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">{</span><span class="pln"> createNote </span><span class="pun">}</span><span class="pln">
</span><span class="pun">)(</span><span class="typ">NewNote</span><span class="pun">)</span></pre>

<p>
	تُمكننا عبارة <code>connect</code> السابقة من إيفاد الأفعال بغية إنشاء ملاحظات جديدة، وذلك باستعمال الأمر <code>('props.createNote('a new note</code>. ينبغي أن تكون الدوال الممررة إلى الدالة <code>mapDispatchToProps</code> مولدات أفعال، أي دوال تعيد أفعال Redux، فلا فائدة من تمرير كائن JavaScript كمعامل لهذه الدالة.
</p>

<p>
	فالتعريف التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3032_38" style="">
<span class="pun">{</span><span class="pln">
  createNote
</span><span class="pun">}</span></pre>

<p>
	هو اختصار لتعريف كائن مجرّد:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3032_40" style="">
<span class="pun">{</span><span class="pln">
  createNote</span><span class="pun">:</span><span class="pln"> createNote
</span><span class="pun">}</span></pre>

<p>
	وهو كائن يمتلك خاصية واحدة هي <code>createNote</code> تأتي مع الدالة <code>createNote</code> كقيمة لها. بدلًا من ذلك، يمكن تمرير التعريف التالي لدالة كمعامل آخر للدالة <code>connect</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3032_42" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">NewNote</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> mapDispatchToProps </span><span class="pun">=</span><span class="pln"> dispatch </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">    
        createNote</span><span class="pun">:</span><span class="pln"> value </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">      
            dispatch</span><span class="pun">(</span><span class="pln">createNote</span><span class="pun">(</span><span class="pln">value</span><span class="pun">))</span><span class="pln">    
        </span><span class="pun">},</span><span class="pln">  
    </span><span class="pun">}}</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> connect</span><span class="pun">(</span><span class="pln">
  </span><span class="kwd">null</span><span class="pun">,</span><span class="pln">
  mapDispatchToProps
</span><span class="pun">)(</span><span class="typ">NewNote</span><span class="pun">)</span></pre>

<p>
	بهذه الطريقة ستدفع الدالة <code>connect</code> بالدالة <code>mapDispatchtoProps</code> بتمريرها لدالة الإيفاد <code>dispatch</code> كمعامل لها. وستكون النتيجة كائن يعرّف مجموعة من الدوال التي ستمرر إلى المكوّن المتصل كخصائص.
</p>

<p>
	يعرّف تطبيقنا الدالة التي ستُمرر إلى <code>connect</code> على أنها الخاصية <code>createNote</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3032_44" style="">
<span class="pln">value </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  dispatch</span><span class="pun">(</span><span class="pln">createNote</span><span class="pun">(</span><span class="pln">value</span><span class="pun">))</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	حيث توفد ببساطة الفعل الذي أنشأته دالة مولد الأفعال <code>createNote</code>. يشير بعدها المكوِّن إلى الدالة عبر خصائصه من خلال الأمر <code>props.creatNote</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3032_46" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">NewNote</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> addNote </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> content </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">note</span><span class="pun">.</span><span class="pln">value
    event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">note</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pln">
    props</span><span class="pun">.</span><span class="pln">createNote</span><span class="pun">(</span><span class="pln">content</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">form onSubmit</span><span class="pun">={</span><span class="pln">addNote</span><span class="pun">}&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">input name</span><span class="pun">=</span><span class="str">"note"</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button type</span><span class="pun">=</span><span class="str">"submit"</span><span class="pun">&gt;</span><span class="pln">add</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يحمل هذا المفهوم شيئًا من التعقيد ويصعب شرحه وتوضيحه من خلال كتابته، ويكفي في معظم الحالات استخدام الشكل الأبسط للدالة <code>mapDispatchToProps</code>. لكن تظهر الحاجة في بعض الحالات إلى استخدام الشكل المعقد، كالحالة التي يتطلب فيها إيفاد الفعل إلى <a data-ss1615734074="1" href="https://github.com/gaearon/redux-devtools/issues/250#issuecomment-186429931" rel="external nofollow">الإشارة المرجعية إلى خصائص الكائن</a>.
</p>

<p>
	أعدّ مصمم Redux دان آبراموف دورة تعليمية مميزة بعنوان <a data-ss1615734074="1" href="https://egghead.io/courses/getting-started-with-redux" rel="external nofollow">Getting started with Redux</a> يمكن أن تجدها على Egghead.io. ننصح الجميع بالاطلاع عليها. وستركز الفيديوهات الأربعة الأخيرة من الدورة على <code>connect</code> وخاصة الطرق الأكثر تعقيدًا في استخدامها.
</p>

<h2>
	مرور آخر على المكونات التقديمية ومكونات الحاويات
</h2>

<p>
	يُركز المكون الذي أعدنا تشكيله كليًا على تصيير الملاحظات، فهو قريب جدًا مما ندعوه <a data-ss1615734074="1" href="https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0" rel="external nofollow">بالمكونات التقديمية</a>. وبناء على <a data-ss1615734074="1" href="https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0" rel="external nofollow">الوصف</a> الذي قدمه دان آبراموف، فالمكونات التقديمية:
</p>

<ul>
<li>
		تهتم بكيفية عرض الأشياء
	</li>
	<li>
		يمكن أن تضم مكوّنات تقديمية أو حاويات، كما قد تحتوي على شيفرة DOM وتنسيقات CSS خاصة بها.
	</li>
	<li>
		غالبًا ما تسمح باحتواء المكوّنات من خلال الخصائص الأبناء pops.children.
	</li>
	<li>
		لا تتعلق ببقية التطبيق، كأفعال Redux أو مخازنها.
	</li>
	<li>
		لا تحدد الطريقة التي تُحمّل بها البيانات أو كيف تتغير.
	</li>
	<li>
		تستقبل البيانات والاستدعاءات من خلال الخصائص حصرًا.
	</li>
	<li>
		بالنادر ما تمتلك حالة مكوّن خاصة بها، وعندما تمتلك حالة فهي حالة واجهة مستخدم أكثر من كونها حالة تخزين بيانات.
	</li>
	<li>
		تُنشأ كمكوّنات وظيفية، إلّا عندما تحتاج إلى حالة أو خطافات دورة عمل أو استمثال أداء.
	</li>
</ul>
<p>
	تحقق المكونات المتصلة التي أنشأتها الدالة <code>connect</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3032_48" style="">
<span class="kwd">const</span><span class="pln"> mapStateToProps </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">filter </span><span class="pun">===</span><span class="pln"> </span><span class="str">'ALL'</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      notes</span><span class="pun">:</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">notes
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    notes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">.</span><span class="pln">filter  </span><span class="pun">===</span><span class="pln"> </span><span class="str">'IMPORTANT'</span><span class="pln"> 
    </span><span class="pun">?</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> note</span><span class="pun">.</span><span class="pln">important</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">:</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">!</span><span class="pln">note</span><span class="pun">.</span><span class="pln">important</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> mapDispatchToProps </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  toggleImportanceOf</span><span class="pun">,</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> connect</span><span class="pun">(</span><span class="pln">
  mapStateToProps</span><span class="pun">,</span><span class="pln">
  mapDispatchToProps
</span><span class="pun">)(</span><span class="typ">Notes</span><span class="pun">)</span></pre>

<p>
	وصف مكونات الحاويات، كما جاء في <a data-ss1615734074="1" href="https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0" rel="external nofollow">وصف</a> دان آبراموف لمكونات الحاويات:
</p>

<ul>
<li>
		تركز على كيفية عمل الأشياء
	</li>
	<li>
		يمكن أن تضم مكونات تقديمية ومكونات حاويات، لكنها لا تحتوي عادة على شيفرة DOM خاصة بها ماعدا بعض عناصر <code>div</code> التي تغلف أجزاء من الشيفرة، ولا تمتلك أية تنسيقات CSS.
	</li>
	<li>
		تزود المكوِّنات التقديمية أو مكونات الحاويات الأخرى بالبيانات أوتزودها بطريقة سلوكها.
	</li>
	<li>
		تطلب أفعال Redux وتزود المكونات التقديمية بها كاستدعاءات.
	</li>
	<li>
		غالبًا ما تحتوي على حالة، فطبيعتها تجعلها تميل إلى تزويد غيرها بالبيانات.
	</li>
	<li>
		تُنشئها عادة المكونات الأعلى مثل <code>connect</code> العائدة للمكتبة React-Redux
	</li>
</ul>
<p>
	إنّ تصنيف المكونات إلى تقديمية ومكونات حاويات هي طريقة لتنظيم هيكلية تطبيقات React. وقد يكون ذلك ميزة تصميمة جيدة وقد لا يكون، حسب الوضع المدروس.
</p>

<p>
	وقد أشار آبراموف إلى <a data-ss1615734074="1" href="https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0" rel="external nofollow">الحسنات</a> التالية لهذا التقسيم:
</p>

<ul>
<li>
		فصل أفضل للمكونات. فستفهم تطبيقك وواجهة المستخدم التي صممتها بشكل أفضل على هذا النحو.
	</li>
	<li>
		قابلية استخدام أفضل. حيث يمكنك استخدام المكونات التقديمية مع مصادر مختلفة للحالة، وتحويل هذه المكونات إلى مكونات حاويات يمكن إعادة استخدامها من جديد.
	</li>
	<li>
		ستؤمن لك المكوّنات التقديمية بشكل رئيسي أدواتك الفنية. حيث يمكنك وضعهم في صفحة واحدة متيحًا للمصمم أن يغيّر ما يشاء دون المساس بمنطق التطبيق. ويمكنك ذلك من اختبار التغيرات في تصميم الصفحة.
	</li>
</ul>
<p>
	ويشير آبراموف إلى مصطلح <a data-ss1615734074="1" href="https://reactjs.org/docs/higher-order-components.html" rel="external nofollow">المكوّن من المرتبة العليا</a>، فالمكوّن <code>Note</code> هو مثال عن المكوّن النظامي، بينما تمثل الدالة <code>connect</code> التي تتبع إلى المكتبة React-Redux مكوّنًا من مرتبة عليا. فالمكونات من مراتب عليا هي بشكل أساسي دوال تقبل مكونات نظامية كمعاملات لها، ومن ثم تعيد مكوّنًا نظاميًا.
</p>

<p>
	تمثل المكوّنات من مراتب عليا (HOCs) طريقة في تعريف الدوال المعمّمة التي يمكن أن تُطبق على المكوّنات. وهو مفهوم يعود أصلًا إلى أسلوب البرمجة بالدوال ويقابل بشكل ما مفهوم الوراثة في البرمجة كائنية التوجه.
</p>

<p>
	تعتبر في واقع الأمر المكونات من المراتب العليا تعميمًا لمفهوم <a data-ss1615734074="1" href="https://en.wikipedia.org/wiki/Higher-order_function" rel="external nofollow">الدوال من المراتب العليا</a> (HOF). وهي دوال قد تقبل دوال أخرى كمعاملات أو أن تعيد دوال. لقد استخدمنا بشكل مستمر خلال المنهاج هذا النوع من الدوال، وكمثال عليها التوابع التي تتعامل مع المصفوفات مثل <code>map</code> و<code>filter</code> و<code>find</code>.
</p>

<p>
	انخفضت شعبية HOCs بعد ظهور واجهة الخطافات البرمجية في React. وعُدّلت جميع المكتبات التي اعتمدت عليها لتستخدم الخطافات. فالخطافات في أغلب الأوقات أسهل استعمالًا من HOC كما هي الحال في Redux.
</p>

<h2>
	المكتبة Redux وحالة المكون
</h2>

<p>
	لقد قطعنا شوطًا طويلًا في هذا المنهاج، ووصلنا إلى النقطة التي أصبحنا قادرين فيها على استخدام React بالطريقة الصحيحة. ويعني هذا أنّ React ستركز على توليد مظهر التطبيق، وستنفصل حالة التطبيق كليًا عن المكوّنات وتُمرر إلى Redux سواء أفعالها أو دوال الاختزال التي تستخدمها.
</p>

<p>
	لكن ما هو وضع الخطاف <code>useState</code> الذي يزوّد المكوّن بحالة خاصة به؟ هل له أي دور في حال استخدم التطبيق Redux أو أي حل آخر لإدارة الحالة؟ إن امتلك التطبيق نماذج أكثر تعقيدًا، فمن الأفضل أن تتمتع بطريقة ذاتية لإدارة حالتها ويكون ذلك باستخدام الدالة<code>useState</code>. وبالطبع نستطيع الاعتماد أيضًا على Redux لإدارة حالة النماذج، لكن من الأفضل ترك إدارة الحالة للمكوّن عندما تتعلق الحالة بملء حقول النموذج مثلًا.
</p>

<p>
	هل ينبغي استخدام Redux دائمًا؟ ربما لا، فقد ناقش دان آبراموف ذلك في مقالته <a data-ss1615734074="1" href="https://medium.com/@dan_abramov/you-might-not-need-redux-be46360cf367" rel="external nofollow">You Might Not Need Redux</a>.
</p>

<p>
	تتوفر حاليًا طرق أخرى لإدارة الحالة بطرق مشابهة للمكتبة Redux كاستخدام الواجهة البرمجية التي تؤمنها React واستخدام الخطاف <a data-ss1615734074="1" href="https://wiki.hsoub.com/React/hooks_reference#useReducer" rel="external">useReducer</a>. يمكن الاطلاع على طريقة <a data-ss1615734074="1" href="https://www.simplethread.com/cant-replace-redux-with-hooks/" rel="external nofollow">عمل الواجهة</a> و<a data-ss1615734074="1" href="https://hswolff.com/blog/how-to-usecontext-with-usereducer/" rel="external nofollow">عمل الخطاف</a> من خلال الانترنت، كما سنناقش ذلك في قسم لاحق.
</p>

<h2>
	التمارين 6.19 - 6.21
</h2>

<h3>
	6.19 تطبيق الطرائف باستخدام connect: الخطوة 1
</h3>

<p>
	يصل المكوّن حاليًا إلى مخزن Redux عبر الخطافين <code>useSelector</code> و<code>useDispatch</code>. عدّل المكوّن <code>AnecdoteList</code> لكي يستخدم الدالة <code>connect</code> بدلًا من الخطافات.
</p>

<p>
	يمكنك استخدام الدوال <code>mapStateToProps</code> و<code>mapDispatchToProps</code> بما تراه مناسبًا.
</p>

<h3>
	6.20 تطبيق الطرائف باستخدام connect: الخطوة 2
</h3>

<p>
	عدّل كما فعلت سابقًا المكوّنين <code>Filter</code> و<code>AncedoteForm</code>.
</p>

<h3>
	6.211 تطبيق الطرائف: الخاتمة
</h3>

<p>
	ربما سنواجه ثغرة مزعجة في التطبيق. إن نقر المستخدم على زر التصويت في سطر واحد عدة مرات ستظهر رسالة التنبيه بشكل مضحك. فإن صوّت المستخدم مرتين خلال ثلاث ثوانٍ، فسيظهر التنبيه الأخير لمدة ثانيتين فقط(على فرض أنّ التنبيه يدوم 5 ثوانٍ بشكل طبيعي). ويحدث ذلك لأنّ إزالة التنبيه الأول يزيل الثاني مصادفةً.
</p>

<p>
	أصلح هذه الثغرة، ليبقى التنبيه الصادر عن آخر تصويت مدة خمس ثوانٍ وذلك عند التصويت لعدة مرات. ويُنفّذ الأمر بإزالة التنبيه السابق عندما يتم عرض التنبيه التالي عندما يكون ذلك ضروريًا. يمكنك الاستفادة من توثيق الدالة <code><a data-ss1615734074="1" href="https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout" rel="external nofollow">setTimeout</a></code> أيضًا.
</p>

<p>
	وهكذا نكون قد وصلنا إلى آخر تمارين القسم وحان الوقت لإرسال الحلول إلى GitHub والإشارة إلى أنك أكملت التمارين ضمن <a data-ss1615734074="1" href="https://studies.cs.helsinki.fi/stats/courses/fullstackopen" rel="external nofollow">منظومة تسليم التمارين</a>.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a data-ss1615734074="1" href="https://fullstackopen.com/en/part6/connect" rel="external nofollow">connect</a> من سلسلة <a data-ss1615734074="1" href="https://fullstackopen.com/en/" rel="external nofollow">Deep Dive Into Modern Web Development</a>
</p>
]]></description><guid isPermaLink="false">1165</guid><pubDate>Sun, 21 Mar 2021 13:01:01 +0000</pubDate></item><item><title>&#x627;&#x644;&#x627;&#x62A;&#x635;&#x627;&#x644; &#x645;&#x639; &#x627;&#x644;&#x62E;&#x627;&#x62F;&#x645; &#x641;&#x64A; &#x62A;&#x637;&#x628;&#x64A;&#x642; React &#x645;&#x639;&#x62A;&#x645;&#x62F; &#x639;&#x644;&#x649; Redux</title><link>https://academy.hsoub.com/programming/javascript/react/%D8%A7%D9%84%D8%A7%D8%AA%D8%B5%D8%A7%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%AE%D8%A7%D8%AF%D9%85-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-react-%D9%85%D8%B9%D8%AA%D9%85%D8%AF-%D8%B9%D9%84%D9%89-redux-r1164/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_03/604e2461c8aaa_-----React---Redux.png.0d02b7aacd305df3d05d780606e0dcce.png" /></p>

<p>
	لنوسّع التطبيق الآن بحيث تُخزَّن الملاحظات في الواجهة الخلفية. سنستخدم في عملنا <a data-ss1615733444="1" data-ss1615733687="1" data-ss1615733848="1" href="https://academy.hsoub.com/programming/javascript/react/%D8%A5%D8%AD%D8%B6%D8%A7%D8%B1-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%85%D9%86-%D8%A7%D9%84%D8%AE%D8%A7%D8%AF%D9%85-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-react-r1096/" rel="">خادم Json</a> الذي خبرناه في القسم 2.
</p>

<p>
	خُزِّنت الحالة الأولية لقاعدة البيانات في الملف "db.json" الموجود في جذر المشروع:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_848_7" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="str">"notes"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
      </span><span class="str">"content"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"the app state is in redux store"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"important"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"id"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
      </span><span class="str">"content"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"state changes are made with actions"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"important"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"id"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">]</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سنثبت خادم JSON من أجل مشروعنا:
</p>

<pre class="ipsCode">
npm install json-server --save-dev
</pre>

<p>
	أضف الشيفرة التالية إلى قسم السكربت في الملف "package.json":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_848_9" style="">
<span class="str">"scripts"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="str">"server"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"json-server -p3001 --watch db.json"</span><span class="pun">,</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سنشغّل خادم JSON باستخدام الأمر <code>npm run server</code>. وسننشئ أيضًا تابعًا في الملف "services/notes.js" الذي سيستخدم المكتبة axios لإحضار البيانات من الواجهة الخلفية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_848_11" style="">
<span class="kwd">import</span><span class="pln"> axios from </span><span class="str">'axios'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> baseUrl </span><span class="pun">=</span><span class="pln"> </span><span class="str">'http://localhost:3001/notes'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> getAll </span><span class="pun">=</span><span class="pln"> async </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> response </span><span class="pun">=</span><span class="pln"> await axios</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="pln">baseUrl</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> getAll </span><span class="pun">}</span></pre>

<p>
	يجب إضافة المكتبة axios إلى المشروع:
</p>

<pre class="ipsCode">
npm install axios
</pre>

<p>
	سنغيّر القيمة الأولية للحالة في دالة الاختزال <code>noteReducer</code> بحيث لا تكون هناك أية ملاحظات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_848_13" style="">
<span class="kwd">const</span><span class="pln"> noteReducer </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[],</span><span class="pln"> action</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	من الطرق السريعة لإعداد الحالة بناء على البيانات الموجودة في الخادم هو إحضار الملاحظات الموجودة في الملف "index.js" ثم إيفاد الفعل<code>NEW_NOTE</code> لكلٍ منها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_848_15" style="">
<span class="com">// ...</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> noteService from </span><span class="str">'./services/notes'</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> reducer </span><span class="pun">=</span><span class="pln"> combineReducers</span><span class="pun">({</span><span class="pln">
  notes</span><span class="pun">:</span><span class="pln"> noteReducer</span><span class="pun">,</span><span class="pln">
  filter</span><span class="pun">:</span><span class="pln"> filterReducer</span><span class="pun">,</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> store </span><span class="pun">=</span><span class="pln"> createStore</span><span class="pun">(</span><span class="pln">reducer</span><span class="pun">)</span><span class="pln">

noteService
    </span><span class="pun">.</span><span class="pln">getAll</span><span class="pun">()</span><span class="pln">
    </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">notes </span><span class="pun">=&gt;</span><span class="pln">  
          notes</span><span class="pun">.</span><span class="pln">forEach</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">    
    store</span><span class="pun">.</span><span class="pln">dispatch</span><span class="pun">({</span><span class="pln"> type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'NEW_NOTE'</span><span class="pun">,</span><span class="pln"> data</span><span class="pun">:</span><span class="pln"> note </span><span class="pun">})</span><span class="pln">  
</span><span class="pun">}))</span><span class="pln">
</span><span class="com">// ...</span></pre>

<p>
	سندعم الفعل <code>INIT_NOTES</code> ضمن دالة الاختزال حتى نستطيع إعادة التهيئة باستخدام عملية إيفاد واحدة. سننشئ كذلك الدالة المولدة للأفعال <code>initializeNotes</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_848_17" style="">
<span class="com">// ...</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> noteReducer </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[],</span><span class="pln"> action</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'ACTION:'</span><span class="pun">,</span><span class="pln"> action</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">switch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">action</span><span class="pun">.</span><span class="pln">type</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="str">'NEW_NOTE'</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">[...</span><span class="pln">state</span><span class="pun">,</span><span class="pln"> action</span><span class="pun">.</span><span class="pln">data</span><span class="pun">]</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="str">'INIT_NOTES'</span><span class="pun">:</span><span class="pln">     
      </span><span class="kwd">return</span><span class="pln"> action</span><span class="pun">.</span><span class="pln">data    </span><span class="com">// ...</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> initializeNotes </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">notes</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'INIT_NOTES'</span><span class="pun">,</span><span class="pln">
    data</span><span class="pun">:</span><span class="pln"> notes</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// ...</span></pre>

<p>
	سيصبح الملف "index.js" بالشكل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_848_19" style="">
<span class="kwd">import</span><span class="pln"> noteReducer</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> initializeNotes </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'./reducers/noteReducer'</span><span class="pln">
</span><span class="com">// ...</span><span class="pln">

noteService</span><span class="pun">.</span><span class="pln">getAll</span><span class="pun">().</span><span class="pln">then</span><span class="pun">(</span><span class="pln">notes </span><span class="pun">=&gt;</span><span class="pln">
  store</span><span class="pun">.</span><span class="pln">dispatch</span><span class="pun">(</span><span class="pln">initializeNotes</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">))</span><span class="pln">
</span><span class="pun">)</span></pre>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p>
		ملاحظة: لماذا لم نستخدم await بدلًا من الوعود ومعالجات الأحداث (المعرفة ضمن التابع then)؟ لا تعمل await إلا داخل الدالة async، والشيفرة في الملف index.js ليست ضمن دالة، لذلك لم نستخدم async لبساطة العملية.
	</p>
</blockquote>

<p>
	لكننا قررنا مع ذلك نقل شيفرة التهيئة الأولية للملاحظات إلى المكوّن <code>App</code>، وسنستخدم كالعادة خطاف التأثير لإحضار البيانات من الخادم:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_848_21" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">useEffect</span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react'</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">NewNote</span><span class="pln"> from </span><span class="str">'./components/NewNote'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Notes</span><span class="pln"> from </span><span class="str">'./components/Notes'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">VisibilityFilter</span><span class="pln"> from </span><span class="str">'./components/VisibilityFilter'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> noteService from </span><span class="str">'./services/notes'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> initializeNotes </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'./reducers/noteReducer'</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> useDispatch </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react-redux'</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> dispatch </span><span class="pun">=</span><span class="pln"> useDispatch</span><span class="pun">()</span><span class="pln">
  useEffect</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">    
      noteService      
          </span><span class="pun">.</span><span class="pln">getAll</span><span class="pun">().</span><span class="pln">then</span><span class="pun">(</span><span class="pln">notes </span><span class="pun">=&gt;</span><span class="pln"> dispatch</span><span class="pun">(</span><span class="pln">initializeNotes</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">)))</span><span class="pln">
  </span><span class="pun">},</span><span class="pln"> </span><span class="pun">[])</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">NewNote</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">VisibilityFilter</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Notes</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">App</span></pre>

<p>
	سيعطي المدقق ESlint تحذيرًا عند استخدام خطاف التأثير:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="59617" data-ss1615733444="1" data-ss1615733687="1" data-ss1615733848="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/effecthook_eslint_warn_01.png.0d0feab4b73d43a6b00042df5de66b52.png" rel=""><img alt="effecthook_eslint_warn_01.png" class="ipsImage ipsImage_thumbnailed" data-fileid="59617" data-unique="277uxv5n9" src="https://academy.hsoub.com/uploads/monthly_2021_03/effecthook_eslint_warn_01.png.0d0feab4b73d43a6b00042df5de66b52.png"></a>
</p>

<p>
	يمكن التخلص من هذا التحذير كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_848_23" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> dispatch </span><span class="pun">=</span><span class="pln"> useDispatch</span><span class="pun">()</span><span class="pln">
  useEffect</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    noteService
      </span><span class="pun">.</span><span class="pln">getAll</span><span class="pun">().</span><span class="pln">then</span><span class="pun">(</span><span class="pln">notes </span><span class="pun">=&gt;</span><span class="pln"> dispatch</span><span class="pun">(</span><span class="pln">initializeNotes</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">)))</span><span class="pln">
  </span><span class="pun">},</span><span class="pln"> </span><span class="pun">[</span><span class="pln">dispatch</span><span class="pun">])</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أضف المتغير الذي عرفناه ضمن المكوّن <code>App</code> والذي يمثل عمليًا دالة الإيفاد إلى مخزن Redux، إلى المصفوفة التي يستقبلها خطاف التأثير كمعامل. فإن تغيرت قيمة متغير الإيفاد أثناء التشغيل، سيُنفَّذ التأثير مجددًا. لن يحدث هذا في تطبيقنا، لذلك فالتحذير السابق ليس بذي أهمية.
</p>

<p>
	يمكن التخلص من التحذير السابق أيضًا بإلغاء تدقيق ذلك السطر:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_848_25" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> dispatch </span><span class="pun">=</span><span class="pln"> useDispatch</span><span class="pun">()</span><span class="pln">
  useEffect</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    noteService
      </span><span class="pun">.</span><span class="pln">getAll</span><span class="pun">().</span><span class="pln">then</span><span class="pun">(</span><span class="pln">notes </span><span class="pun">=&gt;</span><span class="pln"> dispatch</span><span class="pun">(</span><span class="pln">initializeNotes</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">)))</span><span class="pln">   
  </span><span class="pun">},[])</span><span class="pln"> </span><span class="com">// eslint-disable-line react-hooks/exhaustive-deps  </span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ليس جيدًا إلغاء عمل المدقق eslint عندما يعطي إنذارًا، وحتى لو سبب المدقق بعض <a data-ss1615733444="1" data-ss1615733687="1" data-ss1615733848="1" href="https://github.com/facebook/create-react-app/issues/6880" rel="external nofollow">الإشكاليات</a> سنعتمد الحل الأول.
</p>

<p>
	يمكنك الاطلاع على معلومات أكثر عن اعتماديات الخطافات في <a data-ss1615733444="1" data-ss1615733687="1" data-ss1615733848="1" href="https://wiki.hsoub.com/React/hooks_faq#.D9.87.D9.84_.D9.85.D9.86_.D8.A7.D9.84.D8.A2.D9.85.D9.86_.D8.AD.D8.B0.D9.81_.D8.A7.D9.84.D8.AF.D9.88.D8.A7.D9.84_.D9.85.D9.86_.D9.82.D8.A7.D8.A6.D9.85.D8.A9_.D8.A7.D9.84.D8.AA.D8.A8.D8.B9.D9.8A.D8.A7.D8.AA.D8.9F" rel="external">توثيق React</a>.
</p>

<p>
	يمكن أن نفعل المثل عندما ننشئ ملاحظة جديدة. لنوسّع شيفرة الاتصال مع الخادم كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_848_28" style="">
<span class="kwd">const</span><span class="pln"> baseUrl </span><span class="pun">=</span><span class="pln"> </span><span class="str">'http://localhost:3001/notes'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> getAll </span><span class="pun">=</span><span class="pln"> async </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> response </span><span class="pun">=</span><span class="pln"> await axios</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="pln">baseUrl</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> createNew </span><span class="pun">=</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">content</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  
    </span><span class="kwd">const</span><span class="pln"> object </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> content</span><span class="pun">,</span><span class="pln"> important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">}</span><span class="pln">  
    </span><span class="kwd">const</span><span class="pln"> response </span><span class="pun">=</span><span class="pln"> await axios</span><span class="pun">.</span><span class="pln">post</span><span class="pun">(</span><span class="pln">baseUrl</span><span class="pun">,</span><span class="pln"> object</span><span class="pun">)</span><span class="pln">  
    </span><span class="kwd">return</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  getAll</span><span class="pun">,</span><span class="pln">
  createNew</span><span class="pun">,</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يتغير التابع <code>addNote</code> العائد للمكوّن <code>NewNote</code> قليلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_848_30" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> useDispatch </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react-redux'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> createNote </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'../reducers/noteReducer'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> noteService from </span><span class="str">'../services/notes'</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">NewNote</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> dispatch </span><span class="pun">=</span><span class="pln"> useDispatch</span><span class="pun">()</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> addNote </span><span class="pun">=</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">    
    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> content </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">note</span><span class="pun">.</span><span class="pln">value
    event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">note</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> newNote </span><span class="pun">=</span><span class="pln"> await noteService</span><span class="pun">.</span><span class="pln">createNew</span><span class="pun">(</span><span class="pln">content</span><span class="pun">)</span><span class="pln">
   dispatch</span><span class="pun">(</span><span class="pln">createNote</span><span class="pun">(</span><span class="pln">newNote</span><span class="pun">))</span><span class="pln">  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">form onSubmit</span><span class="pun">={</span><span class="pln">addNote</span><span class="pun">}&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">input name</span><span class="pun">=</span><span class="str">"note"</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button type</span><span class="pun">=</span><span class="str">"submit"</span><span class="pun">&gt;</span><span class="pln">add</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">NewNote</span></pre>

<p>
	سنغير مولد الأفعال <code>createNote</code> لأنّ الواجهة الخلفية هي من تولد المعرفات الخاصة بالملاحظات (id):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_848_32" style="">
<span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> createNote </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">data</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'NEW_NOTE'</span><span class="pun">,</span><span class="pln">
    data</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يمكن تغيير أهمية الملاحظة باستخدام المبدأ نفسه، أي بتنفيذ طلب غير متزامن إلى الخادم ومن ثم إيفاد الفعل المناسب.
</p>

<p>
	يمكن إيجاد شيفرة التطبيق بوضعه الحالي في الفرع part6-3 ضمن المجلد الخاص بالتطبيق على <a data-ss1615733444="1" data-ss1615733687="1" data-ss1615733848="1" href="https://github.com/fullstack-hy2020/redux-notes/tree/part6-3" rel="external nofollow">GitHub</a>
</p>

<h2>
	التمرينان 6.13 - 6.14
</h2>

<h3>
	6.13 تطبيق الطرائف على الواجهة الخلفية: الخطوة 1
</h3>

<p>
	أحضر الملاحظات من الواجهة الخلفية التي تعمل على خادم JSON بمجرد تشغيل التطبيق. يمكنك الاستعانة بالشيفرة الموجودة على <a data-ss1615733444="1" data-ss1615733687="1" data-ss1615733848="1" href="https://github.com/fullstack-hy2020/misc/blob/master/anecdotes.json" rel="external nofollow">GitHub</a>.
</p>

<h3>
	6.14 تطبيق الطرائف على الواجهة الخلفية: الخطوة 2
</h3>

<p>
	عدّل طريقة إنشاء طرفة جديدة لكي تُخزَّن في الواجهة الخلفية.
</p>

<h2>
	الأفعال غير المتزامنة والمكتبة Redux-Thunk
</h2>

<p>
	مقاربتنا التي اعتمدناها في تطوير التطبيق جيدة، لكن ليس جيدًا أن يجري الاتصال مع الخادم داخل دالة المكوّن. فمن الأفضل أن نفصل شيفرة الاتصال عن المكوّنات، لكي يكون عملها الوحيد هو طلب دالة مولد الأفعال.
</p>

<p>
	في مثالنا السابق، سيهيء المكوّن <code>App</code> حالة التطبيق كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_848_34" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> dispatch </span><span class="pun">=</span><span class="pln"> useDispatch</span><span class="pun">()</span><span class="pln">

  useEffect</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    dispatch</span><span class="pun">(</span><span class="pln">initializeNotes</span><span class="pun">()))</span><span class="pln">  
  </span><span class="pun">},[</span><span class="pln">dispatch</span><span class="pun">])</span><span class="pln"> 

  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وسينشئ المكوّن <code>NewNote</code> ملاحظة جديدة كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3428_7" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">NewNote</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> dispatch </span><span class="pun">=</span><span class="pln"> useDispatch</span><span class="pun">()</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> addNote </span><span class="pun">=</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> content </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">note</span><span class="pun">.</span><span class="pln">value
    event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">note</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pln">
    dispatch</span><span class="pun">(</span><span class="pln">createNote</span><span class="pun">(</span><span class="pln">content</span><span class="pun">))</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيستخدم المكونين الدوال التي تُمرّر إليهما كخصائص فقط، دون الالتفات إلى عملية الاتصال مع الخادم والتي تجري في الكواليس. لنثبت الآن المكتبة <a data-ss1615733444="1" data-ss1615733687="1" data-ss1615733848="1" href="https://github.com/gaearon/redux-thunk" rel="external nofollow">redux-thunk</a> التي تُمكِّن من إنشاء أفعال غير متزامنة كالتالي:
</p>

<pre class="ipsCode">
npm install redux-thunk
</pre>

<p>
	تدعى المكتبة <a data-ss1615733444="1" data-ss1615733687="1" data-ss1615733848="1" href="https://github.com/gaearon/redux-thunk" rel="external nofollow">redux-thunk</a> أحيانًا بأداة Redux الوسطية، والتي يجب أن تهيأ مع المخزن. وطالما وصلنا إلى هذه النقطة، لنفصل إذًا تعريف المخزن ونضعه في ملفه الخاص "src/store.js":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3428_9" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> createStore</span><span class="pun">,</span><span class="pln"> combineReducers</span><span class="pun">,</span><span class="pln"> applyMiddleware </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'redux'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> thunk from </span><span class="str">'redux-thunk'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> composeWithDevTools </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'redux-devtools-extension'</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> noteReducer from </span><span class="str">'./reducers/noteReducer'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> filterReducer from </span><span class="str">'./reducers/filterReducer'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> reducer </span><span class="pun">=</span><span class="pln"> combineReducers</span><span class="pun">({</span><span class="pln">
  notes</span><span class="pun">:</span><span class="pln"> noteReducer</span><span class="pun">,</span><span class="pln">
  filter</span><span class="pun">:</span><span class="pln"> filterReducer</span><span class="pun">,</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> store </span><span class="pun">=</span><span class="pln"> createStore</span><span class="pun">(</span><span class="pln">
  reducer</span><span class="pun">,</span><span class="pln">
  composeWithDevTools</span><span class="pun">(</span><span class="pln">
    applyMiddleware</span><span class="pun">(</span><span class="pln">thunk</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> store</span></pre>

<p>
	سيبدو الملف "src/index.js" بعد التغييرات كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3428_11" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">ReactDOM</span><span class="pln"> from </span><span class="str">'react-dom'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Provider</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react-redux'</span><span class="pln"> 
</span><span class="kwd">import</span><span class="pln"> store from </span><span class="str">'./store'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> from </span><span class="str">'./App'</span><span class="pln">

</span><span class="typ">ReactDOM</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="typ">Provider</span><span class="pln"> store</span><span class="pun">={</span><span class="pln">store</span><span class="pun">}&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">App</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="typ">Provider</span><span class="pun">&gt;,</span><span class="pln">
  document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'root'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">)</span></pre>

<p>
	يمكننا الآن باستخدام المكتبة redux-thunk أن نعرّف مولد أفعال يعيد دالة تحتوي التابع <code>dispatch</code> العائد للمكتبة Redux كمعامل لها. ونتيجة لذلك يمكن إنشاء مولدات أفعال غير متزامنة تنتظر حتى تنتهي عملية ما، ثم توفد الفعل الحقيقي.
</p>

<p>
	سنعرّف الآن مولد الأفعال <code>initializeNotes</code> الذي يهيئ حالة الملاحظات كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3428_13" style="">
<span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> initializeNotes </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> async dispatch </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> notes </span><span class="pun">=</span><span class="pln"> await noteService</span><span class="pun">.</span><span class="pln">getAll</span><span class="pun">()</span><span class="pln">
    dispatch</span><span class="pun">({</span><span class="pln">
      type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'INIT_NOTES'</span><span class="pun">,</span><span class="pln">
      data</span><span class="pun">:</span><span class="pln"> notes</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	كفعل غير متزامن، تحضر العملية كل الملاحظات من الخادم ومن ثم توفدها إلى هذا الفعل الذي يضيفها إلى المخزن. سيُعرَّف المكوّن <code>App</code> الآن كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3428_15" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> dispatch </span><span class="pun">=</span><span class="pln"> useDispatch</span><span class="pun">()</span><span class="pln">

  useEffect</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">    
      dispatch</span><span class="pun">(</span><span class="pln">initializeNotes</span><span class="pun">())</span><span class="pln">   
  </span><span class="pun">},[</span><span class="pln">dispatch</span><span class="pun">])</span><span class="pln"> 
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">NewNote</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">VisibilityFilter</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Notes</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تقدّم الطريقة السابقة حلًا أنيقًا، حيث فُصل منطق عملية تهيئة الملاحظات كليًا خارج مكوّن React. سيبدو مولد الأفعال <code>createNote</code> الذي يُنشئ الملاحظة الجديدة كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3428_17" style="">
<span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> createNote </span><span class="pun">=</span><span class="pln"> content </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> async dispatch </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> newNote </span><span class="pun">=</span><span class="pln"> await noteService</span><span class="pun">.</span><span class="pln">createNew</span><span class="pun">(</span><span class="pln">content</span><span class="pun">)</span><span class="pln">
    dispatch</span><span class="pun">({</span><span class="pln">
      type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'NEW_NOTE'</span><span class="pun">,</span><span class="pln">
      data</span><span class="pun">:</span><span class="pln"> newNote</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	اتبعنا أيضًا المبدأ نفسه، حيث تُنفّذ بداية عملية غير متزامنة، ومن ثم يوفد الفعل الذي سيغير حالة المخزن. سيتغير المكوّن <code>NewNote</code> ليصبح على النحو:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3428_19" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">NewNote</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> dispatch </span><span class="pun">=</span><span class="pln"> useDispatch</span><span class="pun">()</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> addNote </span><span class="pun">=</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> content </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">note</span><span class="pun">.</span><span class="pln">value
    event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">note</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pln">
    dispatch</span><span class="pun">(</span><span class="pln">createNote</span><span class="pun">(</span><span class="pln">content</span><span class="pun">))</span><span class="pln">  
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">form onSubmit</span><span class="pun">={</span><span class="pln">addNote</span><span class="pun">}&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">input name</span><span class="pun">=</span><span class="str">"note"</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button type</span><span class="pun">=</span><span class="str">"submit"</span><span class="pun">&gt;</span><span class="pln">lis</span><span class="pun">ää&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يمكن إيجاد شيفرة التطبيق بوضعه الحالي في الفرع part6-4 ضمن المجلد الخاص بالتطبيق على <a data-ss1615733444="1" data-ss1615733687="1" data-ss1615733848="1" href="https://github.com/fullstack-hy2020/redux-notes/tree/part6-4" rel="external nofollow">GitHub</a>.
</p>

<h2>
	التمارين 6.15 - 6.18
</h2>

<h3>
	6.15 تطبيق الطرائف على الواجهة الخلفية: الخطوة 3
</h3>

<p>
	عدّل الطريقة التي تجري فيها تهيئة مخزن Redux لتستخدم مولدات الأفعال غير المتزامنة، اعتمادًا على المكتبة Redux-Thunk.
</p>

<h3>
	6.16 تطبيق الطرائف على الواجهة الخلفية: الخطوة 4
</h3>

<p>
	عدّل أيضًا طريقة إنشاء طرفة جديدة لتستخدم مولدات الأفعال غير المتزامنة بمساعدة المكتبة Redux-Thunk.
</p>

<h3>
	6.17 تطبيق الطرائف على الواجهة الخلفية: الخطوة 5
</h3>

<p>
	لا تخزّن نتائج عملية التصويت حتى اللحظة ضمن الواجهة الخلفية. أصلح ذلك بمساعدة المكتبة Redux-Thunk.
</p>

<h3>
	6.18 تطبيق الطرائف على الواجهة الخلفية: الخطوة 6
</h3>

<p>
	لاتزال طريقة إنشاء التنبيهات غير مناسبة، طالما أنها تحتاج إلى فعلين وإلى الدالة <code>setTimeOut</code> حتى تُنفَّذ:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3428_21" style="">
<span class="pln">dispatch</span><span class="pun">(</span><span class="pln">setNotification</span><span class="pun">(`</span><span class="kwd">new</span><span class="pln"> anecdote </span><span class="str">'${content}'</span><span class="pun">`))</span><span class="pln">
setTimeout</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  dispatch</span><span class="pun">(</span><span class="pln">clearNotification</span><span class="pun">())</span><span class="pln">
</span><span class="pun">},</span><span class="pln"> </span><span class="lit">5000</span><span class="pun">)</span></pre>

<p>
	أنشئ مولد أفعال غير متزامنة، يؤمن الحصول على التنبيه كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3428_23" style="">
<span class="pln">dispatch</span><span class="pun">(</span><span class="pln">setNotification</span><span class="pun">(`</span><span class="pln">you voted </span><span class="str">'${anecdote.content}'</span><span class="pun">`,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">))</span></pre>

<p>
	يمثل النص الذي ينبغي تصييره المعامل الأول، أما المعامل الثاني فهو الوقت الذي يعرض خلاله التنبيه بالثانية. أضف هذا الأسلوب في إظهار التنبيهات إلى تطبيقك.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a data-ss1615733444="1" data-ss1615733687="1" data-ss1615733848="1" href="https://fullstackopen.com/en/part6/communication_with_server_in_redux" rel="external nofollow">communication with server in redux</a> من سلسلة <a data-ss1615733444="1" data-ss1615733687="1" data-ss1615733848="1" href="https://fullstackopen.com/en/" rel="external nofollow">Deep Dive Into Modern Web Development</a>
</p>
]]></description><guid isPermaLink="false">1164</guid><pubDate>Sun, 14 Mar 2021 14:57:40 +0000</pubDate></item><item><title>&#x641;&#x647;&#x645; &#x62F;&#x648;&#x627;&#x644; &#x627;&#x644;&#x627;&#x62E;&#x62A;&#x632;&#x627;&#x644; &#x627;&#x644;&#x645;&#x62A;&#x639;&#x62F;&#x62F;&#x629; (reducers) &#x641;&#x64A; &#x645;&#x643;&#x62A;&#x628;&#x629; Redux &#x641;&#x64A; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; React</title><link>https://academy.hsoub.com/programming/javascript/react/%D9%81%D9%87%D9%85-%D8%AF%D9%88%D8%A7%D9%84-%D8%A7%D9%84%D8%A7%D8%AE%D8%AA%D8%B2%D8%A7%D9%84-%D8%A7%D9%84%D9%85%D8%AA%D8%B9%D8%AF%D8%AF%D8%A9-reducers-%D9%81%D9%8A-%D9%85%D9%83%D8%AA%D8%A8%D8%A9-redux-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-react-r1163/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_03/604e20e983187_----(reducers)---Redux---React.png.0a67bb3733487d2482ff1f364d99d6c6.png" /></p>

<p>
	لنتابع عملنا على نسخة Redux المبسطة من تطبيق الملاحظات. ولكي نسهل الطريق علينا في تطوير المطلوب، سنعدّل دالة الاختزال بحيث نهيئ حالة المخزّن ليحوي ملاحظتين:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5062_7" style="">
<span class="kwd">const</span><span class="pln"> initialState </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'reducer defines how redux store works'</span><span class="pun">,</span><span class="pln">
    important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'state of store can contain any data'</span><span class="pun">,</span><span class="pln">
    important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">]</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> noteReducer </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state </span><span class="pun">=</span><span class="pln"> initialState</span><span class="pun">,</span><span class="pln"> action</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com">// ...</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> noteReducer</span></pre>

<h2>
	مخزن يضم حالة مركبة
</h2>

<p>
	لنضف إمكانية انتقاء الملاحظات التي ستُعرض للمستخدم. ستحتوي واجهة المستخدم <a data-ss1615732944="1" href="https://wiki.hsoub.com/HTML/input/radio" rel="external">أزرار انتقاء</a> (Radio Buttons) لإنجاز المطلوب.
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="59613" data-unique="y8u5hg2qo" src="https://academy.hsoub.com/uploads/monthly_2021_03/note_filter_ui_01.png.0738e98619cae67f3ddb21f19e86d86c.png" alt="note_filter_ui_01.png"></p>

<p>
	لنبدأ بإضافة بسيطة جدًا ومباشرة للشيفرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5062_9" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">NewNote</span><span class="pln"> from </span><span class="str">'./components/NewNote'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Notes</span><span class="pln"> from </span><span class="str">'./components/Notes'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> filterSelected </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">value</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">    
      console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">value</span><span class="pun">)</span><span class="pln">  
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">NewNote</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">        
      all          
      </span><span class="pun">&lt;</span><span class="pln">input type</span><span class="pun">=</span><span class="str">"radio"</span><span class="pln"> name</span><span class="pun">=</span><span class="str">"filter"</span><span class="pln">          
             onChange</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> filterSelected</span><span class="pun">(</span><span class="str">'ALL'</span><span class="pun">)}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">        
             important    
      </span><span class="pun">&lt;</span><span class="pln">input type</span><span class="pun">=</span><span class="str">"radio"</span><span class="pln"> name</span><span class="pun">=</span><span class="str">"filter"</span><span class="pln">          
             onChange</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> filterSelected</span><span class="pun">(</span><span class="str">'IMPORTANT'</span><span class="pun">)}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">        
             nonimportant 
      </span><span class="pun">&lt;</span><span class="pln">input type</span><span class="pun">=</span><span class="str">"radio"</span><span class="pln"> name</span><span class="pun">=</span><span class="str">"filter"</span><span class="pln">          
             onChange</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> filterSelected</span><span class="pun">(</span><span class="str">'NONIMPORTANT'</span><span class="pun">)}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">      
       </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">      
</span><span class="pun">&lt;</span><span class="typ">Notes</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وطالما أنّ الصفة <code>name</code> هي نفسها لكل أزرار الانتقاء، فستشكِّل هذه الأزرار مجموعة واحدة يمكن اختيار أحدها فقط. تمتلك الأزرار معالج تغيرات وظيفته الحالية طباعة النص الذي يظهر بجوار الزر على الطرفية.
</p>

<p>
	قررنا إضافة وظيفة لانتقاء الملاحظات بتخزين قيمة مُرشّح الانتقاء (filter) في مخزن Redux إلى جانب الملاحظات. ستبدو حالة المخزن بعد إجراء التعديلات على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5062_11" style="">
<span class="pun">{</span><span class="pln">
  notes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="pun">{</span><span class="pln"> content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'reducer defines how redux store works'</span><span class="pun">,</span><span class="pln"> important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="pln"> content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'state of store can contain any data'</span><span class="pun">,</span><span class="pln"> important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">}</span><span class="pln">
  </span><span class="pun">],</span><span class="pln">
  filter</span><span class="pun">:</span><span class="pln"> </span><span class="str">'IMPORTANT'</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ستُخزَّن فقط مصفوفة الملاحظات في حالة المُرشِّح بعد إضافة الوظيفة السابقة إلى التطبيق. سيمتلك الآن كائن الحالة خاصيتين هما <code>notes</code> التي تضم مصفوفة الملاحظات، و<code>filter</code> التي تضم النص الذي يشير إلى الملاحظات التي ينبغي عرضها للمستخدم.
</p>

<h2>
	دوال الاختزال المدمجة
</h2>

<p>
	يمكننا تعديل دالة الاختزال في تطبيقنا لتتعامل مع الشكل الجديد للحالة. لكن من الأفضل في وضعنا هذا تعريف دالة اختزال جديدة خاصة بحالة المرشِّح:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5062_13" style="">
<span class="kwd">const</span><span class="pln"> filterReducer </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state </span><span class="pun">=</span><span class="pln"> </span><span class="str">'ALL'</span><span class="pun">,</span><span class="pln"> action</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">switch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">action</span><span class="pun">.</span><span class="pln">type</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="str">'SET_FILTER'</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> action</span><span class="pun">.</span><span class="pln">filter
    </span><span class="kwd">default</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> state
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تمثل الشيفرة التالية الأفعال التي ستغير حالة المُرشِّح:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5062_15" style="">
<span class="pun">{</span><span class="pln">
  type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'SET_FILTER'</span><span class="pun">,</span><span class="pln">
  filter</span><span class="pun">:</span><span class="pln"> </span><span class="str">'IMPORTANT'</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لننشئ أيضًا دالة توليد أفعال جديدة. وسنكتب الشيفرة اللازمة في وحدة جديدة نضعها في الملف "src/reducers/filterReducer.js":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5062_17" style="">
<span class="kwd">const</span><span class="pln"> filterReducer </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state </span><span class="pun">=</span><span class="pln"> </span><span class="str">'ALL'</span><span class="pun">,</span><span class="pln"> action</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> filterChange </span><span class="pun">=</span><span class="pln"> filter </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'SET_FILTER'</span><span class="pun">,</span><span class="pln">
    filter</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> filterReducer</span></pre>

<p>
	يمكننا كتابة دالة الاختزال الفعلية لتطبيقنا بدمج الدالتين السابقتين باستخدام الدالة <a data-ss1615732944="1" href="https://redux.js.org/api/combinereducers" rel="external nofollow">combineReducers</a>.
</p>

<p>
	لنعرِّف دالة الاختزال المدمجة في الملف "index.js":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5062_19" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">ReactDOM</span><span class="pln"> from </span><span class="str">'react-dom'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> createStore</span><span class="pun">,</span><span class="pln"> combineReducers </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'redux'</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Provider</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react-redux'</span><span class="pln"> 
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> from </span><span class="str">'./App'</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> noteReducer from </span><span class="str">'./reducers/noteReducer'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> filterReducer from </span><span class="str">'./reducers/filterReducer'</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> reducer </span><span class="pun">=</span><span class="pln"> combineReducers</span><span class="pun">({</span><span class="pln">  notes</span><span class="pun">:</span><span class="pln"> noteReducer</span><span class="pun">,</span><span class="pln">  filter</span><span class="pun">:</span><span class="pln"> filterReducer</span><span class="pun">})</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> store </span><span class="pun">=</span><span class="pln"> createStore</span><span class="pun">(</span><span class="pln">reducer</span><span class="pun">)</span><span class="pln">

console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">store</span><span class="pun">.</span><span class="pln">getState</span><span class="pun">())</span><span class="pln">

</span><span class="typ">ReactDOM</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(</span><span class="pln">
  </span><span class="com">/*
  &lt;Provider store={store}&gt;
    &lt;App /&gt;
  &lt;/Provider&gt;,
  */</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">div </span><span class="pun">/&gt;,</span><span class="pln">
  document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'root'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">)</span></pre>

<p>
	وطالما أنّ تطبيقنا سيخفق تمامًا عند بلوغنا هذه النقطة، سنصيّر عنصر <code>div</code> فارغ بدلًا من المكون <code>App</code>. ستُطبع الآن حالة المخزن على الطرفية:
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="59616" data-unique="khh5g0iyl" src="https://academy.hsoub.com/uploads/monthly_2021_03/store_state_comReducers_02.png.80a5376c9fc6ec899d65b49af6babea9.png" alt="store_state_comReducers_02.png"></p>

<p>
	لاحظ أنّ للمخزن الشكل الذي نريده تمامًا. لنلق نظرة أقرب على طريقة إنشاء دالة الاختزال المدمجة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5062_21" style="">
<span class="kwd">const</span><span class="pln"> reducer </span><span class="pun">=</span><span class="pln"> combineReducers</span><span class="pun">({</span><span class="pln">
  notes</span><span class="pun">:</span><span class="pln"> noteReducer</span><span class="pun">,</span><span class="pln">
  filter</span><span class="pun">:</span><span class="pln"> filterReducer</span><span class="pun">,</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	إنّ حالة المخزن التي عرفناها في الشيفرة السابقة، هي كائن له خاصيتين: <code>notes</code> و<code>filter</code>. تُعرَّف قيمة الخاصية من خلال الدالة <code>noteReducer</code> والتي لن تتعامل مع الخواص الأخرى للكائن، كما تتحكم الدالة <code>filterReducer</code> بالخاصية الأخرى <code>filter</code> فقط.
</p>

<p>
	قبل أن نتابع سلسلة التغيرات التي نجريها على الشيفرة، لنلق نظرة على طريقة تغيير حالة المخزن باستخدام الأفعال التي تُعرِّفها دوال الاختزال المدمجة. لنضف الشيفرة التالية إلى الملف "index.js":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5062_23" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> createNote </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'./reducers/noteReducer'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> filterChange </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'./reducers/filterReducer'</span><span class="pln">
</span><span class="com">//...</span><span class="pln">
store</span><span class="pun">.</span><span class="pln">subscribe</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">store</span><span class="pun">.</span><span class="pln">getState</span><span class="pun">()))</span><span class="pln">
store</span><span class="pun">.</span><span class="pln">dispatch</span><span class="pun">(</span><span class="pln">filterChange</span><span class="pun">(</span><span class="str">'IMPORTANT'</span><span class="pun">))</span><span class="pln">
store</span><span class="pun">.</span><span class="pln">dispatch</span><span class="pun">(</span><span class="pln">createNote</span><span class="pun">(</span><span class="str">'combineReducers forms one reducer from many simple reducers'</span><span class="pun">))</span></pre>

<p>
	بمحاكاة الطريقة التي تُنشأ بها الملاحظة الجديدة ومحاكاة التغييرات التي تطرأ على حالة المرشِّح بهذا الأسلوب، ستُطبع حالة المخزن على الطرفية في كل مرة يحدث فيها تغيير على المخزن:
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="59615" data-unique="uy9pa2max" src="https://academy.hsoub.com/uploads/monthly_2021_03/state_changes_logged_03.png.d0eeec5e66bee3947b8c8e95af622c9f.png" alt="state_changes_logged_03.png"></p>

<p>
	ويجدر بك الآن أن تنتبه إلى تفصيل صغير لكنه هام، فلو أضفنا أمر الطباعة إلى الطرفية في بداية كلتا دالتي الاختزال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5062_25" style="">
<span class="kwd">const</span><span class="pln"> filterReducer </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state </span><span class="pun">=</span><span class="pln"> </span><span class="str">'ALL'</span><span class="pun">,</span><span class="pln"> action</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'ACTION: '</span><span class="pun">,</span><span class="pln"> action</span><span class="pun">)</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	فقد يُهيّأ للشخص بناءً على ما طُبع في الطرفية، أنّ كل فعل قد نُفِّذ مرتين:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-ss1615732944="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/action_seems_dupicated_04.png.66bdf6211750980866036601666a17ce.png" data-fileid="59607" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="59607" data-unique="04l4ke619" src="https://academy.hsoub.com/uploads/monthly_2021_03/action_seems_dupicated_04.png.66bdf6211750980866036601666a17ce.png" alt="action_seems_dupicated_04.png"></a>
</p>

<p>
	هل هناك ثغرة ياترى في تطبيقنا؟ الجواب هو لا. إذ تقتضي طريقة عمل دوال الاختزال المدمجة التعامل مع كل فعل في كل جزء من الدالة. ومن المفترض أن تهتم دالة اختزال واحدة بفعل محدد، لكن قد تصادفنا حالات تغيّر فيها عدة دوال اختزال الأجزاء التي تتعامل معها من الحالة اعتمادًا على نفس الفعل.
</p>

<h2>
	إكمال شيفرة مُرشِّحات الانتقاء
</h2>

<p>
	لنكمل التطبيق بحيث يستخدم دوال الاختزال المدمجة. سنبدأ بتغيير طريقة تصيير التطبيق، ولنعلّق المخزن ضمنه وذلك بتعديل الملف "index.js"
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5062_27" style="">
<span class="typ">ReactDOM</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="typ">Provider</span><span class="pln"> store</span><span class="pun">={</span><span class="pln">store</span><span class="pun">}&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">App</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="typ">Provider</span><span class="pun">&gt;,</span><span class="pln">
  document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'root'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">)</span></pre>

<p>
	سنصلح تاليًا الثغرة التي نتجت عن توقع الشيفرة بأن تكون حالة التطبيق عبارة عن مصفوفة من الملاحظات:
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="59614" data-unique="9mrghzrbc" src="https://academy.hsoub.com/uploads/monthly_2021_03/state_bug_fixed_05.png.0f4d7d9f095a9ccc36135209a8153504.png" alt="state_bug_fixed_05.png"></p>

<p>
	يمكن إنجاز ذلك بسهولة، لأنّ الملاحظات مخزنة أصلًا في الحقل <code>notes</code> من المخزن. لذلك سيفي التعديل البسيط التالي على دالة الانتقاء بالغرض:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5062_29" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Notes</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> dispatch </span><span class="pun">=</span><span class="pln"> useDispatch</span><span class="pun">()</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> notes </span><span class="pun">=</span><span class="pln"> useSelector</span><span class="pun">(</span><span class="pln">state </span><span class="pun">=&gt;</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">notes</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">Note</span><span class="pln">
          key</span><span class="pun">={</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}</span><span class="pln">
          note</span><span class="pun">={</span><span class="pln">note</span><span class="pun">}</span><span class="pln">
          handleClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> 
            dispatch</span><span class="pun">(</span><span class="pln">toggleImportanceOf</span><span class="pun">(</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">))</span><span class="pln">
          </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">)}</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أعادت دالة الانتقاء سابقًا حالة المخزن بأكملها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5062_31" style="">
<span class="kwd">const</span><span class="pln"> notes </span><span class="pun">=</span><span class="pln"> useSelector</span><span class="pun">(</span><span class="pln">state </span><span class="pun">=&gt;</span><span class="pln"> state</span><span class="pun">)</span></pre>

<p>
	بينما ستعيد الآن الحقل <code>notes</code> فقط:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5062_33" style="">
<span class="kwd">const</span><span class="pln"> notes </span><span class="pun">=</span><span class="pln"> useSelector</span><span class="pun">(</span><span class="pln">state </span><span class="pun">=&gt;</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">notes</span><span class="pun">)</span></pre>

<p>
	لنفصل مرشّح إظهار الملاحظات في مكوِّن خاص به ضمن الملف "src/components/VisibilityFilter.js":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5062_35" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> filterChange </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'../reducers/filterReducer'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> useDispatch </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react-redux'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">VisibilityFilter</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> dispatch </span><span class="pun">=</span><span class="pln"> useDispatch</span><span class="pun">()</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      all    
      </span><span class="pun">&lt;</span><span class="pln">input 
        type</span><span class="pun">=</span><span class="str">"radio"</span><span class="pln"> 
        name</span><span class="pun">=</span><span class="str">"filter"</span><span class="pln"> 
        onChange</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> dispatch</span><span class="pun">(</span><span class="pln">filterChange</span><span class="pun">(</span><span class="str">'ALL'</span><span class="pun">))}</span><span class="pln">
      </span><span class="pun">/&gt;</span><span class="pln">
      important   
      </span><span class="pun">&lt;</span><span class="pln">input
        type</span><span class="pun">=</span><span class="str">"radio"</span><span class="pln">
        name</span><span class="pun">=</span><span class="str">"filter"</span><span class="pln">
        onChange</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> dispatch</span><span class="pun">(</span><span class="pln">filterChange</span><span class="pun">(</span><span class="str">'IMPORTANT'</span><span class="pun">))}</span><span class="pln">
      </span><span class="pun">/&gt;</span><span class="pln">
      nonimportant 
      </span><span class="pun">&lt;</span><span class="pln">input
        type</span><span class="pun">=</span><span class="str">"radio"</span><span class="pln">
        name</span><span class="pun">=</span><span class="str">"filter"</span><span class="pln">
        onChange</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> dispatch</span><span class="pun">(</span><span class="pln">filterChange</span><span class="pun">(</span><span class="str">'NONIMPORTANT'</span><span class="pun">))}</span><span class="pln">
      </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">VisibilityFilter</span></pre>

<p>
	سيصبح المكوِّن <code>App</code> بعد إنشاء المكوِّن السابق بسيطًا كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5062_37" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Notes</span><span class="pln"> from </span><span class="str">'./components/Notes'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">NewNote</span><span class="pln"> from </span><span class="str">'./components/NewNote'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">VisibilityFilter</span><span class="pln"> from </span><span class="str">'./components/VisibilityFilter'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">NewNote</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">VisibilityFilter</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Notes</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">App</span></pre>

<p>
	ستظهر نتيجة الإضافة مباشرة الآن. فبالنقر على أزرار الانتقاء ستتغير حالة الخاصية <code>filter</code> للمخزن. لنغيّر المكوِّن <code>Notes</code> بحيث يتضمن المرشِّح:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5062_39" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Notes</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> dispatch </span><span class="pun">=</span><span class="pln"> useDispatch</span><span class="pun">()</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> notes </span><span class="pun">=</span><span class="pln"> useSelector</span><span class="pun">(</span><span class="pln">state </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">    
      </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">filter </span><span class="pun">===</span><span class="pln"> </span><span class="str">'ALL'</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">      
          </span><span class="kwd">return</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">notes    
      </span><span class="pun">}</span><span class="pln">    
      </span><span class="kwd">return</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">filter  </span><span class="pun">===</span><span class="pln"> </span><span class="str">'IMPORTANT'</span><span class="pln">       
          </span><span class="pun">?</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> note</span><span class="pun">.</span><span class="pln">important</span><span class="pun">)</span><span class="pln">      
      </span><span class="pun">:</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">!</span><span class="pln">note</span><span class="pun">.</span><span class="pln">important</span><span class="pun">)</span><span class="pln">  </span><span class="pun">})</span><span class="pln">
  </span><span class="kwd">return</span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">Note</span><span class="pln">
          key</span><span class="pun">={</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}</span><span class="pln">
          note</span><span class="pun">={</span><span class="pln">note</span><span class="pun">}</span><span class="pln">
          handleClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> 
            dispatch</span><span class="pun">(</span><span class="pln">toggleImportanceOf</span><span class="pun">(</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">))</span><span class="pln">
          </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">)}</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span></pre>

<p>
	نجري التعديلات على دالة الانتقاء فقط، والتي كانت:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5062_41" style="">
<span class="pln">useSelector</span><span class="pun">(</span><span class="pln">state </span><span class="pun">=&gt;</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">notes</span><span class="pun">)</span></pre>

<p>
	لنبسّط دالة الانتقاء بتفكيك حقل الحالة الذي يُمرَّر إليها كمعامل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5062_43" style="">
<span class="kwd">const</span><span class="pln"> notes </span><span class="pun">=</span><span class="pln"> useSelector</span><span class="pun">(({</span><span class="pln"> filter</span><span class="pun">,</span><span class="pln"> notes </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> filter </span><span class="pun">===</span><span class="pln"> </span><span class="str">'ALL'</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> notes
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> filter  </span><span class="pun">===</span><span class="pln"> </span><span class="str">'IMPORTANT'</span><span class="pln"> 
    </span><span class="pun">?</span><span class="pln"> notes</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> note</span><span class="pun">.</span><span class="pln">important</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">:</span><span class="pln"> notes</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">!</span><span class="pln">note</span><span class="pun">.</span><span class="pln">important</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	لكن هناك عيب بسيط في التطبيق. فعلى الرغم من ضبط المرشِّح افتراضيًا على القيمة <code>ALL</code>، لن يُختار أي زر من أزراء الانتقاء. يمكننا إيجاد الحل طبعًا، لكننا سنؤجل ذلك إلى وقت لاحق، طالما أنّ الثغرة لن تتسبب بأية مشاكل سوى أنها غير مرغوبة.
</p>

<h2>
	أدوات تطوير Redux
</h2>

<p>
	يمكن تثبيت الموسِّع <a data-ss1615732944="1" href="https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd" rel="external nofollow">Redux DevTools</a> على المتصفح، الذي يساعد على مراقبة حالة مخزن والأفعال التي تغيّرها من خلال طرفية المتصفح. بالإضافة إلى الموسِّع السابق، يمكننا الاستفادة من المكتبة <a data-ss1615732944="1" href="https://www.npmjs.com/package/redux-devtools-extension" rel="external nofollow">redux-devtools-extension</a> أثناء التنقيح. لنثبت هذه المكتبة كالتالي:
</p>

<pre class="ipsCode">
npm install --save-dev redux-devtools-extension
</pre>

<p>
	سنجري تعديلًا بسيطًا على تعريف المخزن لنتمكن من العمل مع المكتبة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5062_46" style="">
<span class="com">// ...</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> createStore</span><span class="pun">,</span><span class="pln"> combineReducers </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'redux'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> composeWithDevTools </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'redux-devtools-extension'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> noteReducer from </span><span class="str">'./reducers/noteReducer'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> filterReducer from </span><span class="str">'./reducers/filterReducer'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> reducer </span><span class="pun">=</span><span class="pln"> combineReducers</span><span class="pun">({</span><span class="pln">
  notes</span><span class="pun">:</span><span class="pln"> noteReducer</span><span class="pun">,</span><span class="pln">
  filter</span><span class="pun">:</span><span class="pln"> filterReducer
</span><span class="pun">})</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> store </span><span class="pun">=</span><span class="pln"> createStore</span><span class="pun">(</span><span class="pln">
  reducer</span><span class="pun">,</span><span class="pln">
  composeWithDevTools</span><span class="pun">())</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> store</span></pre>

<p>
	عندما نفتح الطرفية الآن، ستبدو نافذة Redux كالتالي:
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="59612" data-unique="skff7kyg2" src="https://academy.hsoub.com/uploads/monthly_2021_03/console_redux_tab_06.png.112819a40e31cb6bf46a6be1fe8505a8.png" alt="console_redux_tab_06.png"></p>

<p>
	يمكن بسهولة مراقبة كل فعل يجري على المخزن كما يُظهر الشكل التالي:
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="59611" data-unique="16qdl5spi" src="https://academy.hsoub.com/uploads/monthly_2021_03/console_actions_monitoring_07.png.33a914363716b11448ccd9876d78ab44.png" alt="console_actions_monitoring_07.png"></p>

<p>
	كما يمكن إيفاد الأفعال إلى المخزن مستخدمين الطرفية كالتالي:
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="59610" data-unique="b1q3h5lrw" src="https://academy.hsoub.com/uploads/monthly_2021_03/console_action_dispatch_08.png.dc28f4f8cff529ae6287702a7a1f22be.png" alt="console_action_dispatch_08.png"></p>

<p>
	يمكنك إيجاد الشيفرة الكاملة لتطبيقنا الحالي في الفرع part6-2 من المستودع المخصص للتطبيق على <a data-ss1615732944="1" href="https://github.com/fullstack-hy2020/redux-notes/tree/part6-2" rel="external nofollow">GitHub</a>.
</p>

<h2>
	التمارين 6.9 - 6.12
</h2>

<p>
	لنكمل العمل على تطبيق الطرائف باستخدام Redux والذي بدأناه في الفصل السابق.
</p>

<h3>
	6.9 تطبيق طرائف أفضل: الخطوة 7
</h3>

<p>
	ابدأ باستخدام Redux DevTools. وانقل تعريف مخزن Redux إلى ملف خاص به وسمّه "store.js"
</p>

<h3>
	6.10 تطبيق طرائف أفضل: الخطوة 8
</h3>

<p>
	يمتلك التطبيق جسمًا معدًا مسبقًا يضم المكوَّن <code>Notification</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5062_50" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Notification</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> style </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    border</span><span class="pun">:</span><span class="pln"> </span><span class="str">'solid'</span><span class="pun">,</span><span class="pln">
    padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln">
    borderWidth</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div style</span><span class="pun">={</span><span class="pln">style</span><span class="pun">}&gt;</span><span class="pln">
      render here notification</span><span class="pun">...</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">Notification</span></pre>

<p>
	وسّع المكوِّن ليصيّر الرسالة المخزنّة في مخزن Redux، وليأخذ الشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5062_52" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> useSelector </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react-redux'</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Notification</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> notification </span><span class="pun">=</span><span class="pln"> useSelector</span><span class="pun">(</span><span class="com">/* something here */</span><span class="pun">)</span><span class="pln">  
  </span><span class="kwd">const</span><span class="pln"> style </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    border</span><span class="pun">:</span><span class="pln"> </span><span class="str">'solid'</span><span class="pun">,</span><span class="pln">
    padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln">
    borderWidth</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div style</span><span class="pun">={</span><span class="pln">style</span><span class="pun">}&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">notification</span><span class="pun">}</span><span class="pln">    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	عليك أن تجري تعديلات على دالة الاختزال الموجودة في التطبيق. أنشئ دالة اختزال جديدة للوظيفة الجديدة، ثم أعد كتابة التطبيق ليستخدم دالة اختزال مدمجة كما فعلنا سابقًا في هذا الفصل.
</p>

<p>
	لا تستخدم المكوّن <code>Notification</code> لغير الغرض الذي أنشئ لأجله حاليًا. يكفي أن يُظهر التطبيق القيمة الأولية للرسالة في الدالة <code>notificationReducer</code>.
</p>

<h3>
	6.11 تطبيق طرائف أفضل: الخطوة 9
</h3>

<p>
	وسّع التطبيق لكي يعرض المكون الرسالة مدة 5 ثوانٍ، وذلك عندما يصوّت المستخدم لصالح طرفة أو عندما ينشئ طرفة جديدة.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-ss1615732944="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/anecnode_vote_message_09.png.fee4cb087ca0da6d2d295b8f195912d9.png" data-fileid="59608" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="59608" data-unique="7yn04u10t" src="https://academy.hsoub.com/uploads/monthly_2021_03/anecnode_vote_message_09.png.fee4cb087ca0da6d2d295b8f195912d9.png" alt="anecnode_vote_message_09.png"></a>
</p>

<p>
	ننصحك بإنشاء <a data-ss1615732944="1" href="https://redux.js.org/basics/actions#action-creators" rel="external nofollow">دالة مولد أفعال</a> منفصلة من أجل ضبط و حذف التنبيهات.
</p>

<h3>
	6.12 تطبيق طرائف أفضل: الخطوة 10 *
</h3>

<p>
	أضف وظيفة لانتقاء الطرائف التي ستعرض للمستخدم.
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="59609" data-unique="h41lmher8" src="https://academy.hsoub.com/uploads/monthly_2021_03/anecnodes_filter_10..png.dd439d8f61e0a73906e0d7aa39c41797.png" alt="anecnodes_filter_10..png"></p>

<p>
	خزّن حالة المرشِّح في مخزن Redux. ويفضّل إنشاء دالة اختزال ومولد أفعال جديدين لهذه الغاية. أنشئ المكوّن الجديد <code>Filter</code> لعرض الطرائف التي تم انتقاؤها. يمكنك استخدام الشيفرة التالية كقالب للمكوِّن:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5062_54" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Filter</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> handleChange </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// input-field value is in variable event.target.value</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> style </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    marginBottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div style</span><span class="pun">={</span><span class="pln">style</span><span class="pun">}&gt;</span><span class="pln">
      filter </span><span class="pun">&lt;</span><span class="pln">input onChange</span><span class="pun">={</span><span class="pln">handleChange</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">Filter</span></pre>

<p>
	ترجمة -وبتصرف- للفصل <a data-ss1615732944="1" href="https://fullstackopen.com/en/part1/Many_reducers" rel="external nofollow">Many reducers</a> من سلسلة <a data-ss1615732944="1" href="https://fullstackopen.com/en/" rel="external nofollow">Deep Dive Into Modern Web Development</a>
</p>
]]></description><guid isPermaLink="false">1163</guid><pubDate>Sun, 14 Mar 2021 13:00:00 +0000</pubDate></item><item><title>&#x627;&#x633;&#x62A;&#x639;&#x645;&#x627;&#x644; &#x627;&#x644;&#x645;&#x639;&#x645;&#x627;&#x631;&#x64A;&#x629; Flux &#x648;&#x627;&#x644;&#x645;&#x643;&#x62A;&#x628;&#x629; Redux &#x644;&#x625;&#x62F;&#x627;&#x631;&#x629; &#x627;&#x644;&#x62D;&#x627;&#x644;&#x629; &#x641;&#x64A; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; React</title><link>https://academy.hsoub.com/programming/javascript/react/%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D8%A7%D9%84%D9%85%D8%B9%D9%85%D8%A7%D8%B1%D9%8A%D8%A9-flux-%D9%88%D8%A7%D9%84%D9%85%D9%83%D8%AA%D8%A8%D8%A9-redux-%D9%84%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D8%AD%D8%A7%D9%84%D8%A9-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-react-r1162/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_03/604e1d6d5df95_--Flux--Redux-----React.png.6a10026af7631350e6b9f68b55f64a72.png" /></p>

<p>
	لقد اتبعنا حتى هذه اللحظة التقاليد التي تنصح بها React في إدارة الحالة. حيث وضعنا الحالة والتوابع التي تتعامل معها في <a data-ss1615732041="1" data-ss1615732607="1" href="https://wiki.hsoub.com/React/lifting_state_up" rel="external">المكوِّن الجذري</a> للتطبيق. وهكذا أمكننا تمرير الحالة وتوابعها إلى بقية المكونات من خلال الخصائص. يمكن اعتماد الأسلوب السابق إلى حد معين، لكن بمجرد أن ينمو التطبيق، ستواجهنا العديد من التحديات المتعلقة بإدارة الحالة.
</p>

<h2>
	المعمارية Flux
</h2>

<p>
	طورت Facebook المعمارية <a data-ss1615732041="1" data-ss1615732607="1" href="https://facebook.github.io/flux/docs/in-depth-overview" rel="external nofollow">Flux</a> لتسهيل إدارة الحالة في التطبيقات. حيث تُفصل الحالة في هذه المعمارية بشكل كامل عن المكوِّنات ضمن مخازنها الخاصة. لا تتغير الحالة الموجودة في المخازن مباشرة، بل عبر العديد من الأفعال. فعندما يغير الفعل حالة المخزن، يُعاد تصيير المشهد كاملًا:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="59606" data-ss1615732041="1" data-ss1615732607="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/store_state_changed_01.png.562896bc952ed4e67cebe41df5870694.png" rel=""><img alt="store_state_changed_01.png" class="ipsImage ipsImage_thumbnailed" data-fileid="59606" data-unique="x9miohw4o" src="https://academy.hsoub.com/uploads/monthly_2021_03/store_state_changed_01.thumb.png.fd11308b8517ccde81c3fa5fdca64e64.png"></a>
</p>

<p>
	وإن ولدت بعض الأفعال، كنقر زرٍ مثلًا، الحاجة إلى تغيير حالة التطبيق، سيجري هذا التغيير من خلال فعل، ويسبب ذلك أيضًا إعادة تصيير المشهد من جديد:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="59605" data-ss1615732041="1" data-ss1615732607="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/store_changed_by_action_02.png.0bb8aba518bb6185f9d859ccd030b3d2.png" rel=""><img alt="store_changed_by_action_02.png" class="ipsImage ipsImage_thumbnailed" data-fileid="59605" data-unique="ahhts439j" src="https://academy.hsoub.com/uploads/monthly_2021_03/store_changed_by_action_02.thumb.png.96aef06d9e4d475dcf1eaf0c53631cc5.png"></a>
</p>

<p>
	تقدم Flux طريقة معيارية عن كيفية ومكان حفظ الحالة وعن كيفية تعديلها.
</p>

<h2>
	المكتبة Redux
</h2>

<p>
	قدّمت FaceBook طريقة لاستخدام معمارية Flux، لكننا سنستخدم المكتبة <a data-ss1615732041="1" data-ss1615732607="1" href="https://redux.js.org/" rel="external nofollow">Redux</a>. تعمل هذه المكتبة وفق المبدأ نفسه، لكنها أسهل قليلًا. كما أنّ Facebook نفسها بدأت باستخدام Redux بدلًا من الطريقة التي ابتكرتها. سنتعرف على أسلوب عمل Redux من خلال إنشاء تطبيق العداد مرة أخرى:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="59604" data-ss1615732041="1" data-ss1615732607="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/Redux_imp_03.png.84e8cb60040524ef0bb581c46aebca11.png" rel=""><img alt="Redux_imp_03.png" class="ipsImage ipsImage_thumbnailed" data-fileid="59604" data-unique="rom2rcjp4" src="https://academy.hsoub.com/uploads/monthly_2021_03/Redux_imp_03.png.84e8cb60040524ef0bb581c46aebca11.png"></a>
</p>

<p>
	أنشئ تطبيقًا باستخدام create<em>react</em>app وثبِّت Redux كالتالي: <a data-ss1615732041="1" data-ss1615732607="1" href="https://redux.js.org/" rel="external nofollow">Redux</a>
</p>

<pre class="ipsCode">
npm install redux
</pre>

<p>
	تُخزّن الحالة في Redux في <a data-ss1615732041="1" data-ss1615732607="1" href="https://redux.js.org/basics/store" rel="external nofollow">المخازن</a>، كما هو الحال في Flux.
</p>

<p>
	تُخزَّن حالة التطبيق بأكملها ضمن كائن JavaScript واحد ويوضع في مخزن. لكن طالما أن تطبيقنا سيحتاج إلى قيمة العداد فقط، سنحفظه مباشرة في المخزن (دون الحاجة لوضعه في كائن JavaScript أولًا). بينما لو كانت الحالة أكثر تعقيدًا، لابدّ من حفظ كل جزء ضمن حقل منفصل من حقول كائن JavaScript.
</p>

<p>
	تتغير حالة المخزن من خلال <a data-ss1615732041="1" data-ss1615732607="1" href="https://redux.js.org/basics/actions" rel="external nofollow">الأفعال</a> والتي تُعرّف بأنها كائنات تحتوي على الأقل حقلًا واحدًا يحدد نوع الفعل. سيحتاج تطبيقنا على سبيل المثال هذا النوع من الأفعال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_7" style="">
<span class="pun">{</span><span class="pln">
  type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'INCREMENT'</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وإن تطلب الفعل وجود بيانات أخرى، يمكن أن نعرف حقولًا جديدة ونضعها فيها. لكن تطبيق العداد بسيط ولا يتطلب سوى الحقل الذي يحدد نوع الفعل.
</p>

<p>
	يُحدَّد تأثير الفعل على حالة التطبيق باستخدام دوال الاختزال <a data-ss1615732041="1" data-ss1615732607="1" href="https://redux.js.org/basics/reducers" rel="external nofollow">reducer</a>. وهي في الواقع دوال يُمرر إليها كل من الحالة في وضعها الراهن والفعل كمعاملين. تعيد هذه الدوال الحالة الجديدة.
</p>

<p>
	لنعرّف الآن دالة اختزال في تطبيقنا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_9" style="">
<span class="kwd">const</span><span class="pln"> counterReducer </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">,</span><span class="pln"> action</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">action</span><span class="pun">.</span><span class="pln">type </span><span class="pun">===</span><span class="pln"> </span><span class="str">'INCREMENT'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> state </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">action</span><span class="pun">.</span><span class="pln">type </span><span class="pun">===</span><span class="pln"> </span><span class="str">'DECREMENT'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> state </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">action</span><span class="pun">.</span><span class="pln">type </span><span class="pun">===</span><span class="pln"> </span><span class="str">'ZERO'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> state
</span><span class="pun">}</span></pre>

<p>
	نلاحظ أن الوسيط الأول هو الحالة والثاني هو الفعل. تُعيد دالة الاختزال حالة جديدة وفقًا لنوع الفعل. لنغيّر الشيفرة قليلًا. فمن العادة استخدام بنية التعداد <a data-ss1615732041="1" data-ss1615732607="1" href="https://wiki.hsoub.com/JavaScript/switch" rel="external">switch</a> بدلًا من البنية الشرطية <code>if</code> في دوال الاختزال. ولنجعل أيضًا القيمة 0 <a data-ss1615732041="1" data-ss1615732607="1" href="https://wiki.hsoub.com/JavaScript/Functions#.D8.A7.D9.84.D9.85.D8.B9.D8.A7.D9.85.D9.84.D8.A7.D8.AA_.D8.A7.D9.84.D8.A7.D9.81.D8.AA.D8.B1.D8.A7.D8.B6.D9.8A.D8.A9" rel="external">قيمة افتراضية</a> للحالة. وهكذا ستعمل دالة الاختزال حتى لو لم تُحَّدد الحالة بعد:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_11" style="">
<span class="kwd">const</span><span class="pln"> counterReducer </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> action</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">switch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">action</span><span class="pun">.</span><span class="pln">type</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="str">'INCREMENT'</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> state </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="str">'DECREMENT'</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> state </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="str">'ZERO'</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
    </span><span class="kwd">default</span><span class="pun">:</span><span class="pln"> </span><span class="com">// إن لم نحصل على إحدى الحالات السابقة </span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> state
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	من غير المفترض أن تُستدعى دالة الاختزال مباشرة من خلال شيفرة التطبيق. حيث تُمرَّر هذه الدوال كوسطاء إلى الدالة <code>createStore</code> التي تُنشئ مخزنًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_13" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> createStore </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'redux'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> counterReducer </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> action</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> store </span><span class="pun">=</span><span class="pln"> createStore</span><span class="pun">(</span><span class="pln">counterReducer</span><span class="pun">)</span></pre>

<p>
	سيستخدم المخزن الآن دالة الاختزال للتعامل مع الأفعال التي تُرسل إلى المخزن من خلال التابع <a data-ss1615732041="1" data-ss1615732607="1" href="https://redux.js.org/api/store#dispatchaction" rel="external nofollow">dispatch</a>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_15" style="">
<span class="pln">store</span><span class="pun">.</span><span class="pln">dispatch</span><span class="pun">({</span><span class="pln">type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'INCREMENT'</span><span class="pun">})</span></pre>

<p>
	كما يمكن إيجاد حالة مخزن باستخدام الأمر <a data-ss1615732041="1" data-ss1615732607="1" href="https://redux.js.org/api/store#getstate" rel="external nofollow">getState</a>. ستطبع على سبيل المثال الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_17" style="">
<span class="kwd">const</span><span class="pln"> store </span><span class="pun">=</span><span class="pln"> createStore</span><span class="pun">(</span><span class="pln">counterReducer</span><span class="pun">)</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">store</span><span class="pun">.</span><span class="pln">getState</span><span class="pun">())</span><span class="pln">
store</span><span class="pun">.</span><span class="pln">dispatch</span><span class="pun">({</span><span class="pln">type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'INCREMENT'</span><span class="pun">})</span><span class="pln">
store</span><span class="pun">.</span><span class="pln">dispatch</span><span class="pun">({</span><span class="pln">type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'INCREMENT'</span><span class="pun">})</span><span class="pln">
store</span><span class="pun">.</span><span class="pln">dispatch</span><span class="pun">({</span><span class="pln">type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'INCREMENT'</span><span class="pun">})</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">store</span><span class="pun">.</span><span class="pln">getState</span><span class="pun">())</span><span class="pln">
store</span><span class="pun">.</span><span class="pln">dispatch</span><span class="pun">({</span><span class="pln">type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'ZERO'</span><span class="pun">})</span><span class="pln">
store</span><span class="pun">.</span><span class="pln">dispatch</span><span class="pun">({</span><span class="pln">type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'DECREMENT'</span><span class="pun">})</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">store</span><span class="pun">.</span><span class="pln">getState</span><span class="pun">())</span></pre>

<p>
	المعلومات التالية على الطرفية:
</p>

<pre class="ipsCode">
0
3
-1
</pre>

<p>
	حيث كانت القيمة الافتراضية للحالة هي 0. لكن بعد ثلاثة أفعال زيادة <code>INCREMENT</code>، أصبحت قيمة الحالة 3. وأخيرُا بعد تنفيذ فعل التصفير <code>ZERO</code> وفعل الإنقاص <code>DECREMENT</code> أصبحت قيمة الحالة -1.
</p>

<p>
	يستخدم التابع <a data-ss1615732041="1" data-ss1615732607="1" href="https://redux.js.org/api/store#subscribelistener" rel="external nofollow">subscribe</a> الذي يعود لكائن المخزن في إنشاء دوال الاستدعاء التي يستخدمها المخزن عندما تتغير حالته. فلو أضفنا على سبيل المثال الدالة التالية إلى التابع <code>subscribe</code>، فسيُطبع كل تغيير في الحالة على الطرفية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_20" style="">
<span class="pln">store</span><span class="pun">.</span><span class="pln">subscribe</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> storeNow </span><span class="pun">=</span><span class="pln"> store</span><span class="pun">.</span><span class="pln">getState</span><span class="pun">()</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">storeNow</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	وهكذا سيؤدي تنفيذ الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_22" style="">
<span class="kwd">const</span><span class="pln"> store </span><span class="pun">=</span><span class="pln"> createStore</span><span class="pun">(</span><span class="pln">counterReducer</span><span class="pun">)</span><span class="pln">

store</span><span class="pun">.</span><span class="pln">subscribe</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> storeNow </span><span class="pun">=</span><span class="pln"> store</span><span class="pun">.</span><span class="pln">getState</span><span class="pun">()</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">storeNow</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

store</span><span class="pun">.</span><span class="pln">dispatch</span><span class="pun">({</span><span class="pln"> type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'INCREMENT'</span><span class="pln"> </span><span class="pun">})</span><span class="pln">
store</span><span class="pun">.</span><span class="pln">dispatch</span><span class="pun">({</span><span class="pln"> type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'INCREMENT'</span><span class="pln"> </span><span class="pun">})</span><span class="pln">
store</span><span class="pun">.</span><span class="pln">dispatch</span><span class="pun">({</span><span class="pln"> type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'INCREMENT'</span><span class="pln"> </span><span class="pun">})</span><span class="pln">
store</span><span class="pun">.</span><span class="pln">dispatch</span><span class="pun">({</span><span class="pln"> type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'ZERO'</span><span class="pln"> </span><span class="pun">})</span><span class="pln">
store</span><span class="pun">.</span><span class="pln">dispatch</span><span class="pun">({</span><span class="pln"> type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'DECREMENT'</span><span class="pln"> </span><span class="pun">})</span></pre>

<p>
	إلى طباعة ما يلي على الطرفية:
</p>

<pre class="ipsCode">
1
2
3
0
-1
</pre>

<p>
	تمثل الشيفرة التالية شيفرة تطبيق العداد وقد كتبت جميعها في نفس الملف. لاحظ أننا استخدمنا المخازن بشكل مباشر ضمن شيفرة React. سنتعلم لاحقًا طرقًا أفضل لبناء شيفرة React/Redux
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_24" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">ReactDOM</span><span class="pln"> from </span><span class="str">'react-dom'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> createStore </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'redux'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> counterReducer </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> action</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">switch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">action</span><span class="pun">.</span><span class="pln">type</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="str">'INCREMENT'</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> state </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="str">'DECREMENT'</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> state </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="str">'ZERO'</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
    </span><span class="kwd">default</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> state
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> store </span><span class="pun">=</span><span class="pln"> createStore</span><span class="pun">(</span><span class="pln">counterReducer</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">store</span><span class="pun">.</span><span class="pln">getState</span><span class="pun">()}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button 
        onClick</span><span class="pun">={</span><span class="pln">e </span><span class="pun">=&gt;</span><span class="pln"> store</span><span class="pun">.</span><span class="pln">dispatch</span><span class="pun">({</span><span class="pln"> type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'INCREMENT'</span><span class="pln"> </span><span class="pun">})}</span><span class="pln">
      </span><span class="pun">&gt;</span><span class="pln">
        plus
      </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button
        onClick</span><span class="pun">={</span><span class="pln">e </span><span class="pun">=&gt;</span><span class="pln"> store</span><span class="pun">.</span><span class="pln">dispatch</span><span class="pun">({</span><span class="pln"> type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'DECREMENT'</span><span class="pln"> </span><span class="pun">})}</span><span class="pln">
      </span><span class="pun">&gt;</span><span class="pln">
        minus
      </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button 
        onClick</span><span class="pun">={</span><span class="pln">e </span><span class="pun">=&gt;</span><span class="pln"> store</span><span class="pun">.</span><span class="pln">dispatch</span><span class="pun">({</span><span class="pln"> type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'ZERO'</span><span class="pln"> </span><span class="pun">})}</span><span class="pln">
      </span><span class="pun">&gt;</span><span class="pln">
        zero
      </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> renderApp </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="typ">ReactDOM</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(&lt;</span><span class="typ">App</span><span class="pln"> </span><span class="pun">/&gt;,</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'root'</span><span class="pun">))</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

renderApp</span><span class="pun">()</span><span class="pln">
store</span><span class="pun">.</span><span class="pln">subscribe</span><span class="pun">(</span><span class="pln">renderApp</span><span class="pun">)</span></pre>

<p>
	ستجد عدة نقاط ملفتة في الشيفرة السابقة. سيصير المكوِّن <code>App</code> قيمة العداد بالحصول على قيمته من المخزن باستخدام التابع <code>()store.getState</code>. كما ستوفد معالجات الأفعال المعرّفة في الأزرار الأفعال المناسبة إلى المخزن.
</p>

<p>
	لن تتمكن React من تصيير التطبيق تلقائيًا عندما تتغير حالة المخزن، ولهذا فقد هيئنا الدالة <code>renderApp</code> التي تصيّر التطبيق بأكمله لكي ترصد التغييرات في المخزن عن طريق وضعها ضمن التابع <code>store.subscribe</code>.
</p>

<p>
	لاحظ أنه علينا استدعاء التابع <code>renderApp</code> مباشرة، وبدونه لن يُصيَّر المكوِّن <code>App</code> للمرة الأولى.
</p>

<h2>
	استخدام Redux مع تطبيق الملاحظات
</h2>

<p>
	هدفنا في الفقرات التالية تعديل تطبيق الملاحظات لاستخدام Redux في إدارة الحالة. لكن قبل ذلك سنغطي بعض المفاهيم المفتاحية عبر إنشاء تطبيق ملاحظات مبسط، بحيث تكون للنسخة الأولى منه الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_26" style="">
<span class="kwd">const</span><span class="pln"> noteReducer </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[],</span><span class="pln"> action</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">action</span><span class="pun">.</span><span class="pln">type </span><span class="pun">===</span><span class="pln"> </span><span class="str">'NEW_NOTE'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    state</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">action</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> state
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> state
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> store </span><span class="pun">=</span><span class="pln"> createStore</span><span class="pun">(</span><span class="pln">noteReducer</span><span class="pun">)</span><span class="pln">

store</span><span class="pun">.</span><span class="pln">dispatch</span><span class="pun">({</span><span class="pln">
  type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'NEW_NOTE'</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'the app state is in redux store'</span><span class="pun">,</span><span class="pln">
    important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

store</span><span class="pun">.</span><span class="pln">dispatch</span><span class="pun">({</span><span class="pln">
  type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'NEW_NOTE'</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'state changes are made with actions'</span><span class="pun">,</span><span class="pln">
    important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">store</span><span class="pun">.</span><span class="pln">getState</span><span class="pun">().</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note</span><span class="pun">=&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="pln">li key</span><span class="pun">={</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}&gt;</span><span class="pln">
            </span><span class="pun">{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">content</span><span class="pun">}</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">strong</span><span class="pun">&gt;{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">important </span><span class="pun">?</span><span class="pln"> </span><span class="str">'important'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">''</span><span class="pun">}&lt;/</span><span class="pln">strong</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">)}</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لا يمتلك التطبيق بشكله الحالي وظيفة إضافة ملاحظات جديدة، على الرغم من إمكانية إضافتها من خلال إيفاد الفعل <code>NEW_NOTE</code> إلى المخزن.
</p>

<p>
	لاحظ امتلاك الأفعال الآن حقلًا للنوع وآخر للبيانات ويحتوي على الملاحظة الجديدة التي سنضيفها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_28" style="">
<span class="pun">{</span><span class="pln">
  type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'NEW_NOTE'</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'state changes are made with actions'</span><span class="pun">,</span><span class="pln">
    important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	الدوال النقيّة والدوال الثابتة
</h2>

<p>
	للنسخة الأولية من دالة الاختزال الشكل البسيط التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_30" style="">
<span class="kwd">const</span><span class="pln"> noteReducer </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[],</span><span class="pln"> action</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">action</span><span class="pun">.</span><span class="pln">type </span><span class="pun">===</span><span class="pln"> </span><span class="str">'NEW_NOTE'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    state</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">action</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> state
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> state
</span><span class="pun">}</span></pre>

<p>
	تتخذ الحالة الآن شكل مصفوفة. وتسبب الأفعال من النوع <code>NEW_NOTE</code> إضافة ملاحظة جديدة إلى الحالة عبر التابع <a data-ss1615732041="1" data-ss1615732607="1" href="https://wiki.hsoub.com/JavaScript/Array/push" rel="external">push</a>.
</p>

<p>
	سيعمل التطبيق، لكن دالة الاختزال قد عُرِّفت بطريقة سيئة لأنها ستخرق <a data-ss1615732041="1" data-ss1615732607="1" href="https://github.com/reactjs/redux/blob/master/docs/basics/Reducers.md#handling-actions" rel="external nofollow">الافتراض الرئيسي</a> لدوال الاختزال والذي ينص على أن دوال الاختزال يجب أن تكون دوال نقيّة <a data-ss1615732041="1" data-ss1615732607="1" href="https://en.wikipedia.org/wiki/Pure_function" rel="external nofollow">pure functions</a>.
</p>

<p>
	الدوال النقية هي دوال لا تسبب أية تأثيرات جانبية وعليها أن تعيد نفس الاستجابة عندما تُستدعى بنفس المعاملات.
</p>

<p>
	أضفنا ملاحظة جديدة إلى الحالة مستخدمين التابع <code>(state.push(action.data</code> الذي يغير وضع كائن الحالة. لكن هذا الأمر غير مسموح.
</p>

<p>
	يمكن حل المشكلة بسهولة باستخدام التابع <a data-ss1615732041="1" data-ss1615732607="1" href="https://wiki.hsoub.com/JavaScript/Array/concat" rel="external">concat</a> الذي ينشئ مصفوفة جديدة تحتوي كل عناصر المصفوفة القديمة بالإضافة إلى العنصر الجديد:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_32" style="">
<span class="kwd">const</span><span class="pln"> noteReducer </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[],</span><span class="pln"> action</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">action</span><span class="pun">.</span><span class="pln">type </span><span class="pun">===</span><span class="pln"> </span><span class="str">'NEW_NOTE'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">concat</span><span class="pun">(</span><span class="pln">action</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> state
</span><span class="pun">}</span></pre>

<p>
	كما ينبغي أن تتكون دوال الاختزال من كائنات ثابتة (<a data-ss1615732041="1" data-ss1615732607="1" href="https://en.wikipedia.org/wiki/Immutable_object" rel="external nofollow">immutable</a>). فلو حدث تغيّر في الحالة، فلن يغير ذلك كائن الحالة، بل سيُستبدل بكائن جديد يحتوي الحالة الجديدة. وهذا ما فعلناه تمامًا بدالة الاختزال الجديدة، حين استبدلنا المصفوفة القديمة بالجديدة.
</p>

<p>
	لنوسّع دالة الاختزال لتتمكن من التعامل مع تغيّر أهمية الملاحظة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_34" style="">
<span class="pun">{</span><span class="pln">
  type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'TOGGLE_IMPORTANCE'</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وطالما أننا لم نكتب أية شيفرة للاستفادة من هذه الوظيفة، فما فعلناه هو توسيع دالة الاختزال بالأسلوب "المقاد بالاختبار-Test Driven". لنبدأ إذًا بكتابة اختبار يتعامل مع الفعل <code>NEW_NOTE</code>. ولتسهيل الاختبار، سننقل شيفرة دالة الاختزال إلى وحدة مستقلة ضمن الملف "src/reducers/noteReducer.js". سنضيف أيضًا المكتبة <a data-ss1615732041="1" data-ss1615732607="1" href="https://github.com/substack/deep-freeze" rel="external nofollow">deep-freeze</a> والتي تستخدم للتأكد من تعريف دالة الاختزال كدالة ثابتة. سنثبت المكتبة كاعتمادية تطوير كالتالي:
</p>

<pre class="ipsCode">
npm install --save-dev deep-freeze
</pre>

<p>
	تمثل الشيفرة التالية شيفرة الاختبار الموجود في الملف src/reducers/noteReducer.test.js:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_37" style="">
<span class="kwd">import</span><span class="pln"> noteReducer from </span><span class="str">'./noteReducer'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> deepFreeze from </span><span class="str">'deep-freeze'</span><span class="pln">

describe</span><span class="pun">(</span><span class="str">'noteReducer'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  test</span><span class="pun">(</span><span class="str">'returns new state with action NEW_NOTE'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> state </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> action </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'NEW_NOTE'</span><span class="pun">,</span><span class="pln">
      data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'the app state is in redux store'</span><span class="pun">,</span><span class="pln">
        important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
        id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    deepFreeze</span><span class="pun">(</span><span class="pln">state</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> newState </span><span class="pun">=</span><span class="pln"> noteReducer</span><span class="pun">(</span><span class="pln">state</span><span class="pun">,</span><span class="pln"> action</span><span class="pun">)</span><span class="pln">

    expect</span><span class="pun">(</span><span class="pln">newState</span><span class="pun">).</span><span class="pln">toHaveLength</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
    expect</span><span class="pun">(</span><span class="pln">newState</span><span class="pun">).</span><span class="pln">toContainEqual</span><span class="pun">(</span><span class="pln">action</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	يتوثّق الأمر <code>(deepFreeze(state</code> من أن دالة الاختبار لن تغير حالة المخزن التي تُمرّر إليها كمعامل. وإن استخدمت دالة الاختزال التابع <code>push</code> لتغيير الحالة، سيخفق الاختبار.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="59603" data-ss1615732041="1" data-ss1615732607="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/reducer_deepfreez_04.png.6f1039ccac5f8957e9adb8b1b7f66616.png" rel=""><img alt="reducer_deepfreez_04.png" class="ipsImage ipsImage_thumbnailed" data-fileid="59603" data-unique="dxwiozu8c" src="https://academy.hsoub.com/uploads/monthly_2021_03/reducer_deepfreez_04.png.6f1039ccac5f8957e9adb8b1b7f66616.png"></a>
</p>

<p>
	سنكتب الآن اختبارًا للفعل <code>TOGGLE_IMPORTANT</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_39" style="">
<span class="pln">test</span><span class="pun">(</span><span class="str">'returns new state with action TOGGLE_IMPORTANCE'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> state </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
      content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'the app state is in redux store'</span><span class="pun">,</span><span class="pln">
      important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
      id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
      content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'state changes are made with actions'</span><span class="pun">,</span><span class="pln">
      important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
      id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
    </span><span class="pun">}]</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> action </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'TOGGLE_IMPORTANCE'</span><span class="pun">,</span><span class="pln">
    data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  deepFreeze</span><span class="pun">(</span><span class="pln">state</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> newState </span><span class="pun">=</span><span class="pln"> noteReducer</span><span class="pun">(</span><span class="pln">state</span><span class="pun">,</span><span class="pln"> action</span><span class="pun">)</span><span class="pln">

  expect</span><span class="pun">(</span><span class="pln">newState</span><span class="pun">).</span><span class="pln">toHaveLength</span><span class="pun">(</span><span class="lit">2</span><span class="pun">)</span><span class="pln">

  expect</span><span class="pun">(</span><span class="pln">newState</span><span class="pun">).</span><span class="pln">toContainEqual</span><span class="pun">(</span><span class="pln">state</span><span class="pun">[</span><span class="lit">0</span><span class="pun">])</span><span class="pln">

  expect</span><span class="pun">(</span><span class="pln">newState</span><span class="pun">).</span><span class="pln">toContainEqual</span><span class="pun">({</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'state changes are made with actions'</span><span class="pun">,</span><span class="pln">
    important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	سيغيّر الفعل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_41" style="">
<span class="pun">{</span><span class="pln">
  type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'TOGGLE_IMPORTANCE'</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أهمية الملاحظة التي تحمل المعرّف الفريد 2.
</p>

<p>
	سنوسع التطبيق كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_43" style="">
<span class="kwd">const</span><span class="pln"> noteReducer </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[],</span><span class="pln"> action</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">switch</span><span class="pun">(</span><span class="pln">action</span><span class="pun">.</span><span class="pln">type</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="str">'NEW_NOTE'</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">concat</span><span class="pun">(</span><span class="pln">action</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="str">'TOGGLE_IMPORTANCE'</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">const</span><span class="pln"> id </span><span class="pun">=</span><span class="pln"> action</span><span class="pun">.</span><span class="pln">data</span><span class="pun">.</span><span class="pln">id
      </span><span class="kwd">const</span><span class="pln"> noteToChange </span><span class="pun">=</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="pln">n </span><span class="pun">=&gt;</span><span class="pln"> n</span><span class="pun">.</span><span class="pln">id </span><span class="pun">===</span><span class="pln"> id</span><span class="pun">)</span><span class="pln">
      </span><span class="kwd">const</span><span class="pln"> changedNote </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
        </span><span class="pun">...</span><span class="pln">noteToChange</span><span class="pun">,</span><span class="pln"> 
        important</span><span class="pun">:</span><span class="pln"> </span><span class="pun">!</span><span class="pln">noteToChange</span><span class="pun">.</span><span class="pln">important 
      </span><span class="pun">}</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln">
        note</span><span class="pun">.</span><span class="pln">id </span><span class="pun">!==</span><span class="pln"> id </span><span class="pun">?</span><span class="pln"> note </span><span class="pun">:</span><span class="pln"> changedNote 
      </span><span class="pun">)</span><span class="pln">
     </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">default</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> state
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أنشأنا نسخة من الملاحظة التي غيّرنا أهميتها بالطريقة التي اتبعناها في القسم 2، كما استبدلنا الحالة بأخرى جديدة تضم الملاحظات القديمة التي لم تتغير أهميتها ونسخة عن الملاحظة التي تغيرت أهميتها <code>changedNote</code>. لنلخص ما يجري عند تنفيذ الشيفرة. ففي البداية سنبحث عن كائن الملاحظة التي نريد أن نغير أهميتها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_45" style="">
<span class="kwd">const</span><span class="pln"> noteToChange </span><span class="pun">=</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="pln">n </span><span class="pun">=&gt;</span><span class="pln"> n</span><span class="pun">.</span><span class="pln">id </span><span class="pun">===</span><span class="pln"> id</span><span class="pun">)</span></pre>

<p>
	سننشئ بعد ذلك كائنًا جديدًا يمثل نسخة عن الملاحظة الأصلية، لكن أهميتها قد تغيرت إلى الحالة المعاكسة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_47" style="">
<span class="kwd">const</span><span class="pln"> changedNote </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
  </span><span class="pun">...</span><span class="pln">noteToChange</span><span class="pun">,</span><span class="pln"> 
  important</span><span class="pun">:</span><span class="pln"> </span><span class="pun">!</span><span class="pln">noteToChange</span><span class="pun">.</span><span class="pln">important 
</span><span class="pun">}</span></pre>

<p>
	تُعاد بعد ذلك الحالة الجديدة. وذلك بأخذ جميع الملاحظات القديمة التي لم تتغير حالتها واستبدال الملاحظة التي تغيرت بالنسخة المعدلّة عنها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_49" style="">
<span class="pln">state</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln">
  note</span><span class="pun">.</span><span class="pln">id </span><span class="pun">!==</span><span class="pln"> id </span><span class="pun">?</span><span class="pln"> note </span><span class="pun">:</span><span class="pln"> changedNote 
</span><span class="pun">)</span></pre>

<h2>
	العبارات البرمجية لنشر مصفوفة
</h2>

<p>
	نمتلك الآن اختبارين جيدين لدوال الاختزال، لذلك يمكننا إعادة كتابة الشيفرة لإضافة ملاحظة جديدة تنشئ حالة تعيدها دالة المصفوفات <code>concat</code>. لنلق نظرة على كيفية إنجاز المطلوب باستخدام عامل <a data-ss1615732607="1" href="https://wiki.hsoub.com/JavaScript/Spread_Operator" rel="external">نشر المصفوفة</a>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_51" style="">
<span class="kwd">const</span><span class="pln"> noteReducer </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[],</span><span class="pln"> action</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">switch</span><span class="pun">(</span><span class="pln">action</span><span class="pun">.</span><span class="pln">type</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="str">'NEW_NOTE'</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">[...</span><span class="pln">state</span><span class="pun">,</span><span class="pln"> action</span><span class="pun">.</span><span class="pln">data</span><span class="pun">]</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="str">'TOGGLE_IMPORTANCE'</span><span class="pun">:</span><span class="pln">
      </span><span class="com">// ...</span><span class="pln">
    </span><span class="kwd">default</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> state
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ستعمل دالة نشر المصفوفة على النحو التالي: لو عرفنا المتغير <code>number</code> كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_53" style="">
<span class="kwd">const</span><span class="pln"> numbers </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">]</span></pre>

<p>
	سيفصل الأمر <code>number...</code> المصفوفة إلى عناصرها المفردة بحيث يمكن وضع هذه العناصر في مصفوفة أخرى كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_55" style="">
<span class="pun">[...</span><span class="pln">numbers</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">]</span></pre>

<p>
	وستكون النتيجة <code>[1,2,3,4,5]</code>.
</p>

<p>
	لكن لو استخدمنا المصفوفة دون نشر كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_57" style="">
<span class="pun">[</span><span class="pln">numbers</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">]</span></pre>

<p>
	ستكون النتيجة <code>[4,5,[1,2,3]]</code>.
</p>

<p>
	كما ستبدو الشيفرة مشابهة لما سبق، عندما نفكك المصفوفة إلى عناصرها باستخدام التابع <a data-ss1615732041="1" data-ss1615732607="1" href="https://wiki.hsoub.com/JavaScript/Destructuring_Assignment" rel="external">destructuring</a>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_59" style="">
<span class="kwd">const</span><span class="pln"> numbers </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6</span><span class="pun">]</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">first</span><span class="pun">,</span><span class="pln"> second</span><span class="pun">,</span><span class="pln"> </span><span class="pun">...</span><span class="pln">rest</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> numbers

console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">first</span><span class="pun">)</span><span class="pln">     </span><span class="com">// prints 1</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">second</span><span class="pun">)</span><span class="pln">   </span><span class="com">// prints 2</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">rest</span><span class="pun">)</span><span class="pln">     </span><span class="com">// prints [3, 4, 5, 6]</span></pre>

<h2>
	التمرينات 6.1 - 6.2
</h2>

<p>
	لنكتب نسخة بسيطة عن تطبيق unicafe الذي أنشأناه في القسم 1، بحيث ندير الحالة باستخدام Redux.
</p>

<p>
	يمكنك الحصول على المشروع من المستودع الخاص بالتطبيق على <a data-ss1615732041="1" data-ss1615732607="1" href="https://github.com/fullstack-hy2020/unicafe-redux" rel="external nofollow">GitHub</a> لتستعمله كأساس لمشروعك.
</p>

<p>
	إبدأ عملك بإزالة تهيئة git للنسخة التي لديك، ثم تثبيت الاعتماديات اللازمة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_61" style="">
<span class="pln">cd unicafe</span><span class="pun">-</span><span class="pln">redux   </span><span class="com">// تنقلك هذه التعليمة إلى مجلد المستودع الذي يضمن نسختك</span><span class="pln">
rm </span><span class="pun">-</span><span class="pln">rf </span><span class="pun">.</span><span class="pln">git
npm install</span></pre>

<h3>
	6.1 unicafe مرور ثانٍ: الخطوة 1
</h3>

<p>
	قبل أن نضيف الوظائف إلى واجهة المستخدم، سنعمل على إضافة وظيفة مستودع الحالة. إذ علينا أن نخزّن عدد الآراء من كل نوع وسيبدو شكل المخزن كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_63" style="">
<span class="pun">{</span><span class="pln">
  good</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln">
  ok</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln">
  bad</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيكون لدالة الاختزال الأساسية الشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_65" style="">
<span class="kwd">const</span><span class="pln"> initialState </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  good</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln">
  ok</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln">
  bad</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> counterReducer </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state </span><span class="pun">=</span><span class="pln"> initialState</span><span class="pun">,</span><span class="pln"> action</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">action</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">switch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">action</span><span class="pun">.</span><span class="pln">type</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="str">'GOOD'</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> state
    </span><span class="kwd">case</span><span class="pln"> </span><span class="str">'OK'</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> state
    </span><span class="kwd">case</span><span class="pln"> </span><span class="str">'BAD'</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> state
    </span><span class="kwd">case</span><span class="pln"> </span><span class="str">'ZERO'</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> state
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> state
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> counterReducer</span></pre>

<p>
	وتمثل الشيفرة التالية أساسًا للاختبارات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_67" style="">
<span class="kwd">import</span><span class="pln"> deepFreeze from </span><span class="str">'deep-freeze'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> counterReducer from </span><span class="str">'./reducer'</span><span class="pln">

describe</span><span class="pun">(</span><span class="str">'unicafe reducer'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> initialState </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    good</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln">
    ok</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln">
    bad</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  test</span><span class="pun">(</span><span class="str">'should return a proper initial state when called with undefined state'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> state </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> action </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'DO_NOTHING'</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">const</span><span class="pln"> newState </span><span class="pun">=</span><span class="pln"> counterReducer</span><span class="pun">(</span><span class="kwd">undefined</span><span class="pun">,</span><span class="pln"> action</span><span class="pun">)</span><span class="pln">
    expect</span><span class="pun">(</span><span class="pln">newState</span><span class="pun">).</span><span class="pln">toEqual</span><span class="pun">(</span><span class="pln">initialState</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">

  test</span><span class="pun">(</span><span class="str">'good is incremented'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> action </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'GOOD'</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> state </span><span class="pun">=</span><span class="pln"> initialState

    deepFreeze</span><span class="pun">(</span><span class="pln">state</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> newState </span><span class="pun">=</span><span class="pln"> counterReducer</span><span class="pun">(</span><span class="pln">state</span><span class="pun">,</span><span class="pln"> action</span><span class="pun">)</span><span class="pln">
    expect</span><span class="pun">(</span><span class="pln">newState</span><span class="pun">).</span><span class="pln">toEqual</span><span class="pun">({</span><span class="pln">
      good</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
      ok</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln">
      bad</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	<strong>إضافة الاختبارات ودالة الاختزال: </strong>تأكد من خلال الاختبارات أن دالة الاختزال ثابتة، مستخدمًا المكتبة deep-freeze. وتأكد من نجاح الاختبار الأول، إذ ستتوقع Redux أن تعيد دالة الاختزال قيمة منطقية للحالة الأصلية عند استدعائها، ذلك أن المعامل <code>state</code> الذي يمثل الحالة السابقة، لن يكون معرّفًا في البداية.
</p>

<p>
	وسّع بعد ذلك دالة الاختزال بحيث ينجح الاختباران، ثم أضف بقية الاختبارات. وأخيرًا أضف الوظائف التي سُتختبر. يمكنك الاستعانة بنموذج دالة الاختزال الذي اعتمدناه في تطبيق الملاحظات السابق.
</p>

<h3>
	6.2 unicafe مرور ثانٍ: الخطوة 2
</h3>

<p>
	أضف الآن الوظائف الفعلية للتطبيق.
</p>

<h3>
	النماذج الحرّة
</h3>

<p>
	سنضيف تاليًا وظيفةً لإنشاء ملاحظة جديدة وتغيير أهميتها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_69" style="">
<span class="kwd">const</span><span class="pln"> generateId </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln">
  </span><span class="typ">Number</span><span class="pun">((</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">()</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">1000000</span><span class="pun">).</span><span class="pln">toFixed</span><span class="pun">(</span><span class="lit">0</span><span class="pun">))</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> addNote </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> content </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">note</span><span class="pun">.</span><span class="pln">value
    event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">note</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pln">
    store</span><span class="pun">.</span><span class="pln">dispatch</span><span class="pun">({</span><span class="pln">
      type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'NEW_NOTE'</span><span class="pun">,</span><span class="pln">
      data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        content</span><span class="pun">,</span><span class="pln">
        important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
        id</span><span class="pun">:</span><span class="pln"> generateId</span><span class="pun">()</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> toggleImportance </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">id</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    store</span><span class="pun">.</span><span class="pln">dispatch</span><span class="pun">({</span><span class="pln">
      type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'TOGGLE_IMPORTANCE'</span><span class="pun">,</span><span class="pln">
      data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> id </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">form onSubmit</span><span class="pun">={</span><span class="pln">addNote</span><span class="pun">}&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">input name</span><span class="pun">=</span><span class="str">"note"</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln"> 
        </span><span class="pun">&lt;</span><span class="pln">button type</span><span class="pun">=</span><span class="str">"submit"</span><span class="pun">&gt;</span><span class="pln">add</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">store</span><span class="pun">.</span><span class="pln">getState</span><span class="pun">().</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="pln">li
            key</span><span class="pun">={</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}</span><span class="pln"> 
            onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> toggleImportance</span><span class="pun">(</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">)}</span><span class="pln">
          </span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">content</span><span class="pun">}</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">strong</span><span class="pun">&gt;{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">important </span><span class="pun">?</span><span class="pln"> </span><span class="str">'important'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">''</span><span class="pun">}&lt;/</span><span class="pln">strong</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">)}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ستجري إضافة الوظيفتين بشكل مباشر. وانتبه إلى أننا لم نربط حالة حقول النموذج بحالة المكوّن <code>App</code> كما فعلنا سابقًا، ويعرف هذا النوع من النماذج في React بالنماذج الحرة (<a data-ss1615732041="1" data-ss1615732607="1" href="http://wiki.hsoub.com/React/uncontrolled_components" rel="external">uncontrolled forms</a>).
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p>
		تخضع النماذج الحرة لقيود محددة (فلا يمكن على سبيل المثال إظهار رسائل خطأ ديناميكية، أو تعطيل زر الإرسال بناء على القيم المدخلة). لكنها ستفي بالغرض حاليًا.
	</p>
</blockquote>

<p>
	يمكنك الاطلاع على المزيد حول النماذج الحرة من خلال <a data-ss1615732041="1" data-ss1615732607="1" href="https://goshakkk.name/controlled-vs-uncontrolled-inputs-react/" rel="external nofollow">الانترنت</a>.
</p>

<p>
	تجري إضافة ملاحظة جديدة بإسلوب بسيط، حيث تضاف الملاحظة الجديدة حالما يُوفد الفعل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_71" style="">
<span class="pln">addNote </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> content </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">note</span><span class="pun">.</span><span class="pln">value  event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">note</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pln">
  store</span><span class="pun">.</span><span class="pln">dispatch</span><span class="pun">({</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'NEW_NOTE'</span><span class="pun">,</span><span class="pln">
    data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      content</span><span class="pun">,</span><span class="pln">
      important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
      id</span><span class="pun">:</span><span class="pln"> generateId</span><span class="pun">()</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	كما يمكن الحصول على محتوى الملاحظة الجديدة من الحقل المخصص لها في النموذج مباشرةً. ذلك أننا نستطيع الوصول إلى محتويات الحقل من خلال كائن الحدث باستخدام الأمر <code>event.target.note.value</code>، لأن لهذا الحقل اسمًا محددًا.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1690_75" style="">
<span class="tag">&lt;form</span><span class="pln"> </span><span class="atn">onSubmit</span><span class="pun">={</span><span class="pln">addNote</span><span class="pun">}</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"note"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">  
  </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"submit"</span><span class="tag">&gt;</span><span class="pln">add</span><span class="tag">&lt;/button&gt;</span><span class="pln">
</span><span class="tag">&lt;/form&gt;</span></pre>

<p>
	يمكن تغيير أهمية الملاحظة بالنقر على اسمها، وسيكون لمعالج الحدث الشكل البسيط التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_77" style="">
<span class="pln">toggleImportance </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">id</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  store</span><span class="pun">.</span><span class="pln">dispatch</span><span class="pun">({</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'TOGGLE_IMPORTANCE'</span><span class="pun">,</span><span class="pln">
    data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> id </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	موّلدات الأفعال
</h2>

<p>
	لقد بدأنا نرى أهمية Redux في تبسيط شيفرة الواجهة الأمامية حتى في التطبيقات البسيطة التي أنشأناها، لكن يمكننا أيضًا فعل الكثير. لا حاجة في الواقع أن يعرف مكوّن React أنواع أفعال Redux وأشكالها. سنفصل تاليًا توليد الأفعال إلى دوال خاصة بكل فعل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_79" style="">
<span class="kwd">const</span><span class="pln"> createNote </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">content</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'NEW_NOTE'</span><span class="pun">,</span><span class="pln">
    data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      content</span><span class="pun">,</span><span class="pln">
      important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
      id</span><span class="pun">:</span><span class="pln"> generateId</span><span class="pun">()</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> toggleImportanceOf </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">id</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'TOGGLE_IMPORTANCE'</span><span class="pun">,</span><span class="pln">
    data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> id </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تُدعى الدوال التي تُنشئ الأفعال، <a data-ss1615732041="1" data-ss1615732607="1" href="https://redux.js.org/advanced/async-actions#synchronous-action-creators" rel="external nofollow">مولدات الأفعال</a>. ليس على المكوِّن <code>App</code> أن يعرف أي شيء عن طريقة كتابة الفعل، وكل ما يحتاجه للحصول على الفعل الصحيح هو استدعاء مولد الأفعال.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_81" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> addNote </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> content </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">note</span><span class="pun">.</span><span class="pln">value
    event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">note</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pln">
    store</span><span class="pun">.</span><span class="pln">dispatch</span><span class="pun">(</span><span class="pln">createNote</span><span class="pun">(</span><span class="pln">content</span><span class="pun">))</span><span class="pln">    
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> toggleImportance </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">id</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    store</span><span class="pun">.</span><span class="pln">dispatch</span><span class="pun">(</span><span class="pln">toggleImportanceOf</span><span class="pun">(</span><span class="pln">id</span><span class="pun">))</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	استخدام مخزن Redux ضمن المكونات المختلفة
</h2>

<p>
	باستثناء دالة الاختزال، فقد كُتب تطبيقنا في ملف واحد. وهذا أمر غير منطقي، لذا علينا فصله إلى وحدات مستقلة. لكن السؤال المطروح حاليًا: كيف يمكن للمكوِّن <code>APP</code> أن يصل إلى مخزن الحالة بعد عملية الفصل؟ وبشكل أعم، لا بد من وجود طريقة لوصول كل المكوِّنات الجديدة الناتجة عن تقسيم المكوّن الأصلي إلى مخزن الحالة. هنالك أكثر من طريقة لمشاركة مخزن Redux بين المكوِّنات. سنلقي نظرة أولًا على أسهل طريقة ممكنة وهي استخدام <a data-ss1615732041="1" data-ss1615732607="1" href="https://react-redux.js.org/api/hooks" rel="external nofollow">واجهة الخطافات البرمجية</a> للمكتبة <a data-ss1615732041="1" data-ss1615732607="1" href="https://react-redux.js.org/" rel="external nofollow">react-redux</a>. لنثبت إذًا هذه المكتبة:
</p>

<pre class="ipsCode">
npm install react-redux
</pre>

<p>
	سننقل الآن المكوِّن <code>App</code> إلى وحدة خاصة به يمثلها الملف "App.js"، ولنرى كيف سيؤثر ذلك على بقية ملفات التطبيق. سيصبح الملف "Index.js" على النحو:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_83" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">ReactDOM</span><span class="pln"> from </span><span class="str">'react-dom'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> createStore </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'redux'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Provider</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react-redux'</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> from </span><span class="str">'./App'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> noteReducer from </span><span class="str">'./reducers/noteReducer'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> store </span><span class="pun">=</span><span class="pln"> createStore</span><span class="pun">(</span><span class="pln">noteReducer</span><span class="pun">)</span><span class="pln">

</span><span class="typ">ReactDOM</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="typ">Provider</span><span class="pln"> store</span><span class="pun">={</span><span class="pln">store</span><span class="pun">}&gt;</span><span class="pln">    
    </span><span class="pun">&lt;</span><span class="typ">App</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="typ">Provider</span><span class="pun">&gt;,</span><span class="pln">  
document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'root'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">)</span></pre>

<p>
	لاحظ كيف عُرِّف التطبيق الآن كابن لمكوّن التزويد <a data-ss1615732041="1" data-ss1615732607="1" href="https://react-redux.js.org/api/provider" rel="external nofollow">Provider</a> الذي تقدمه المكتبة React-Redux. وكيف مُرِّر مخزن حالة التطبيق إلى مكوّن التزويد عبر الصفة <code>store</code>. نقلنا تعريف مولدات الأفعال إلى الملف "reducers/noteReducer.js" حيث عرفنا سابقًا دالة الاختزال. سيبدو شكل الملف كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_85" style="">
<span class="kwd">const</span><span class="pln"> noteReducer </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[],</span><span class="pln"> action</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> generateId </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln">
  </span><span class="typ">Number</span><span class="pun">((</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">()</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">1000000</span><span class="pun">).</span><span class="pln">toFixed</span><span class="pun">(</span><span class="lit">0</span><span class="pun">))</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> createNote </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">content</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'NEW_NOTE'</span><span class="pun">,</span><span class="pln">
    data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      content</span><span class="pun">,</span><span class="pln">
      important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
      id</span><span class="pun">:</span><span class="pln"> generateId</span><span class="pun">()</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> toggleImportanceOf </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">id</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'TOGGLE_IMPORTANCE'</span><span class="pun">,</span><span class="pln">
    data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> id </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> noteReducer</span></pre>

<p>
	إن احتوى التطبيق على عدة مكوّنات يحتاج كل منها إلى الوصول إلى مخزن الحالة، يجب على المكوِّن <code>App</code>تمرير المخزن <code>store</code> إليها كخاصية. ستحتوي الوحدة الآن على عدة أوامر <a data-ss1615732041="1" data-ss1615732607="1" href="https://wiki.hsoub.com/JavaScript/export" rel="external">تصدير</a>، سيعيد أمر التصدير الافتراضي دالة الاختزال، لذلك يمكن إدراجها بالطريقة الاعتيادية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_87" style="">
<span class="kwd">import</span><span class="pln"> noteReducer from </span><span class="str">'./reducers/noteReducer'</span></pre>

<p>
	يمكن للوحدة أن تجري عملية تصدير واحدة بشكل افتراضي، وعدة عمليات تصدير اعتيادية.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_89" style="">
<span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> createNote </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">content</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> toggleImportanceOf </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">id</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يمكن إدراج الدوال التي صُدرت بعملية تصدير اعتيادية بوضعها بين قوسين معقوصين:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_91" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> createNote </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'./../reducers/noteReducer'</span></pre>

<p>
	ستصبح شيفرة المكوّن <code>App</code> كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_93" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
  createNote</span><span class="pun">,</span><span class="pln"> toggleImportanceOf
</span><span class="pun">}</span><span class="pln"> from </span><span class="str">'./reducers/noteReducer'</span><span class="pln"> 
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> useSelector</span><span class="pun">,</span><span class="pln"> useDispatch </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react-redux'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> dispatch </span><span class="pun">=</span><span class="pln"> useDispatch</span><span class="pun">()</span><span class="pln">  
  </span><span class="kwd">const</span><span class="pln"> notes </span><span class="pun">=</span><span class="pln"> useSelector</span><span class="pun">(</span><span class="pln">state </span><span class="pun">=&gt;</span><span class="pln"> state</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> addNote </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> content </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">note</span><span class="pun">.</span><span class="pln">value
    event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">note</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pln">
    dispatch</span><span class="pun">(</span><span class="pln">createNote</span><span class="pun">(</span><span class="pln">content</span><span class="pun">))</span><span class="pln">  
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> toggleImportance </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">id</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    dispatch</span><span class="pun">(</span><span class="pln">toggleImportanceOf</span><span class="pun">(</span><span class="pln">id</span><span class="pun">))</span><span class="pln">  
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">form onSubmit</span><span class="pun">={</span><span class="pln">addNote</span><span class="pun">}&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">input name</span><span class="pun">=</span><span class="str">"note"</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln"> 
        </span><span class="pun">&lt;</span><span class="pln">button type</span><span class="pun">=</span><span class="str">"submit"</span><span class="pun">&gt;</span><span class="pln">add</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln">          
         </span><span class="pun">&lt;</span><span class="pln">li
            key</span><span class="pun">={</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}</span><span class="pln"> 
            onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> toggleImportance</span><span class="pun">(</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">)}</span><span class="pln">
          </span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">content</span><span class="pun">}</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">strong</span><span class="pun">&gt;{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">important </span><span class="pun">?</span><span class="pln"> </span><span class="str">'important'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">''</span><span class="pun">}&lt;/</span><span class="pln">strong</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">)}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">App</span></pre>

<p>
	تجدر ملاحظة عدة نقاط في الشيفرة السابقة. فقد جرى سابقًا إيفاد الأفعال باستخدام التابع <code>dispatch</code> العائد لمخزن Redux:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_95" style="">
<span class="pln">store</span><span class="pun">.</span><span class="pln">dispatch</span><span class="pun">({</span><span class="pln">
  type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'TOGGLE_IMPORTANCE'</span><span class="pun">,</span><span class="pln">
  data</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> id </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	أمّا الآن فيجري باستخدام الدالة <code>dispatch</code> العائدة للخطاف <a data-ss1615732041="1" data-ss1615732607="1" href="https://react-redux.js.org/api/hooks#usedispatch" rel="external nofollow">useDispatch</a>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_97" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> useSelector</span><span class="pun">,</span><span class="pln"> useDispatch </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react-redux'</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> dispatch </span><span class="pun">=</span><span class="pln"> useDispatch</span><span class="pun">()</span><span class="pln">  </span><span class="com">// ...</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> toggleImportance </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">id</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    dispatch</span><span class="pun">(</span><span class="pln">toggleImportanceOf</span><span class="pun">(</span><span class="pln">id</span><span class="pun">))</span><span class="pln">  </span><span class="pun">}</span><span class="pln">

  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يؤمن الخطاف <code>useDispatch</code> إمكانية وصول أي مكون من مكونات React إلى الدالة <code>dispatch</code> العائدة لمخزن Redux والمعرّف في الملف "index.js". يسمح هذا الأمر لكل المكونات أن تغير حالة المخزن، فيمكن للمكوِّن الوصول إلى الملاحظات المحفوظة في المخزن باستخدام الخطاف <a data-ss1615732041="1" data-ss1615732607="1" href="https://react-redux.js.org/api/hooks#useselector" rel="external nofollow">useSelector</a> العائد للمكتبة React-Redux:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_99" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> useSelector</span><span class="pun">,</span><span class="pln"> useDispatch </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react-redux'</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> notes </span><span class="pun">=</span><span class="pln"> useSelector</span><span class="pun">(</span><span class="pln">state </span><span class="pun">=&gt;</span><span class="pln"> state</span><span class="pun">)</span><span class="pln">  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يتلقى الخطاف <code>useSelector</code> دالة كمعامل. فإما أن تبحث هذه الدالة عن البيانات أو انتقائها من مخزن Redux. سنحتاج هنا إلى جميع الملاحظات، لذلك ستعيد دالة الانتقاء حالة المخزن كاملةً:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_101" style="">
<span class="pln">state </span><span class="pun">=&gt;</span><span class="pln"> state</span></pre>

<p>
	وهذا الشكل هو اختصار للشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_103" style="">
<span class="pun">(</span><span class="pln">state</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> state
</span><span class="pun">}</span></pre>

<p>
	عادةً ما تستخدم دوال الانتقاء للحصول على أجزاء محددة من محتوى المخزن، فيمكننا على سبيل المثال أن نعيد الملاحظات الهامة فقط:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_105" style="">
<span class="kwd">const</span><span class="pln"> importantNotes </span><span class="pun">=</span><span class="pln"> useSelector</span><span class="pun">(</span><span class="pln">state </span><span class="pun">=&gt;</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> note</span><span class="pun">.</span><span class="pln">important</span><span class="pun">))</span><span class="pln">  </span></pre>

<h2>
	مكوِّنات أكثر
</h2>

<p>
	لنفصل شيفرة إنشاء ملاحظة جديدة، ونضعها في مكوّن خاص بها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_107" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> useDispatch </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react-redux'</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> createNote </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'../reducers/noteReducer'</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">NewNote</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> dispatch </span><span class="pun">=</span><span class="pln"> useDispatch</span><span class="pun">()</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> addNote </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> content </span><span class="pun">=</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">note</span><span class="pun">.</span><span class="pln">value
    event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">note</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> </span><span class="str">''</span><span class="pln">
    dispatch</span><span class="pun">(</span><span class="pln">createNote</span><span class="pun">(</span><span class="pln">content</span><span class="pun">))</span><span class="pln">  
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">form onSubmit</span><span class="pun">={</span><span class="pln">addNote</span><span class="pun">}&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">input name</span><span class="pun">=</span><span class="str">"note"</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button type</span><span class="pun">=</span><span class="str">"submit"</span><span class="pun">&gt;</span><span class="pln">add</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">NewNote</span></pre>

<p>
	وعلى خلاف شيفرة React التي تكتب بمعزل عن Redux، نُقل معالج الحدث الذي يغير حالة التطبيق (والذي يقيم الآن في Redux) من المكوّن الجذري إلى المكوّن الابن. فمنطق تغيير الحالة في Redux يبقى مستقلًا تمامًا عن كامل أجزاء تطبيق React.
</p>

<p>
	كما سنفصل أيضًا قائمة الملاحظات وسنعرض كل ملاحظة ضمن مكوّناتها الخاصة (وسيوضع كلاهما في الملف Notes.js):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_109" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> useDispatch</span><span class="pun">,</span><span class="pln"> useSelector </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react-redux'</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> toggleImportanceOf </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'../reducers/noteReducer'</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Note</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> note</span><span class="pun">,</span><span class="pln"> handleClick </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">li onClick</span><span class="pun">={</span><span class="pln">handleClick</span><span class="pun">}&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">content</span><span class="pun">}</span><span class="pln"> 
      </span><span class="pun">&lt;</span><span class="pln">strong</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">important </span><span class="pun">?</span><span class="pln"> </span><span class="str">'important'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">''</span><span class="pun">}&lt;/</span><span class="pln">strong</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Notes</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> dispatch </span><span class="pun">=</span><span class="pln"> useDispatch</span><span class="pun">()</span><span class="pln">  
</span><span class="kwd">const</span><span class="pln"> notes </span><span class="pun">=</span><span class="pln"> useSelector</span><span class="pun">(</span><span class="pln">state </span><span class="pun">=&gt;</span><span class="pln"> state</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">Note</span><span class="pln">
          key</span><span class="pun">={</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}</span><span class="pln">
          note</span><span class="pun">={</span><span class="pln">note</span><span class="pun">}</span><span class="pln">
          handleClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> 
            dispatch</span><span class="pun">(</span><span class="pln">toggleImportanceOf</span><span class="pun">(</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">))</span><span class="pln">
          </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">)}</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">Notes</span></pre>

<p>
	ستكون الشيفرة المسؤولة عن تغيير أهمية الملاحظة في المكون الذي يدير قائمة الملاحظات، ولم يبق هناك الكثير من الشيفرة في المكوِّن <code>App</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_111" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">NewNote</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Notes</span><span class="pln">  </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	إن شيفرة المكوّن <code>Note</code> المسؤول عن تصيير ملاحظة واحدة بسيطة جدًا، ولا يمكنها معرفة أن معالج الحدث الذي سيمرر لها كخاصّية سيُوفِد فعلًا. يدعى هذا النوع من المكونات وفق مصطلحات React، بالمكوّن التقديمي <a data-ss1615732041="1" data-ss1615732607="1" href="https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0" rel="external nofollow">presentational</a>.
</p>

<p>
	يمثل المكوّن <code>Notes</code> من ناحية أخرى مكوّن احتواء <a data-ss1615732041="1" data-ss1615732607="1" href="https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0" rel="external nofollow">container</a>. فهو يحتوي شيئًا من منطق التطبيق. إذ يُعرِّف ما سيفعله معالج حدث المكوِّن <code>Note</code> ويضبط تهيئة المكوّنات التقديمية وهي في حالتنا المكوّن <code>Note</code>.
</p>

<p>
	سنعود إلى مفهومي مكون الاحتواء والمكون التقديمي لاحقًا في هذا القسم.
</p>

<p>
	يمكنك الحصول على شيفرة تطبيق Redux في الفرع part6-1 ضمن المستودع الخاص بالتطبيق على <a data-ss1615732041="1" data-ss1615732607="1" href="https://github.com/fullstack-hy2020/redux-notes/tree/part6-1" rel="external nofollow">Github</a>.
</p>

<h2>
	التمارين 6.3 - 6.8
</h2>

<p>
	لننشئ نسخة جديدة من تطبيق التصويت على الطرائف الذي كتبناه في <a data-ss1615732607="1" href="https://academy.hsoub.com/programming/javascript/react/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-react-r1072/" rel="">القسم 1</a>. يمكنك الحصول على المشروع من المستودع التالي <a data-ss1615732041="1" data-ss1615732607="1" href="https://github.com/fullstack-hy2020/redux-anecdotes" rel="external nofollow">https://github.com/fullstack-hy2020/redux-anecdotes</a> كأساس لتطبيقك.
</p>

<p>
	إن نسخت المشروع إلى مستودع git موجود مسبقًا أزل تهيئة git لنسختك كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_113" style="">
<span class="pln">cd redux</span><span class="pun">-</span><span class="pln">anecdotes  </span><span class="com">// الذهاب إلى مستودع نسختك من التطبيق</span><span class="pln">
rm </span><span class="pun">-</span><span class="pln">rf </span><span class="pun">.</span><span class="pln">git</span></pre>

<p>
	يمكن أن تشغل التطبيق بالطريق الاعتيادية، لكن عليك أولًا تثبيت الاعتماديات اللازمة:
</p>

<pre class="ipsCode">
npm install
npm start
</pre>

<p>
	بعد إكمال هذه التمارين سيكون لتطبيقك شكلًا مشابهًا للتالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="59602" data-ss1615732041="1" data-ss1615732607="1" href="https://academy.hsoub.com/uploads/monthly_2021_03/ancedotes_redux_05.png.17616ebc3bfee303566e8489b1795990.png" rel=""><img alt="ancedotes_redux_05.png" class="ipsImage ipsImage_thumbnailed" data-fileid="59602" data-unique="b5ifxftfn" src="https://academy.hsoub.com/uploads/monthly_2021_03/ancedotes_redux_05.png.17616ebc3bfee303566e8489b1795990.png"></a>
</p>

<h3>
	6.3 طرائف: الخطوة 1
</h3>

<p>
	أضف وظيفة التصويت على الطرائف. يجب عليك تخزين نتيجة التصويت في مخزن Redux.
</p>

<h3>
	6.4 طرائف: الخطوة 2
</h3>

<p>
	أضف وظيفة إنشاء طرفة جديدة، يمكنك أن تبقي النموذج حرًا كما فعلنا سابقًا في هذا الفصل.
</p>

<h3>
	6.5 طرائف: الخطوة 3 *
</h3>

<p>
	تأكد أنّ الطرائف قد رتبت حسب عدد الأصوات.
</p>

<h3>
	6.6 طرائف: الخطوة 4
</h3>

<p>
	إن لم تكن قد فعلت ذلك، إفصل شيفرة إنشاء كائنات الأفعال وضعها في دالة توليد أفعال، ثم ضعهم في الملف src/reducers/anecdoteReducer.js. يمكنك اتباع الطريقة التي استخدمناها في هذا الفصل، بعد أن تعرفنا على مولدات الأفعال.
</p>

<h3>
	6.7 طرائف: الخطوة 7
</h3>

<p>
	أنشئ مكوِّنًا جديدًا وسمّه <code>AnecdoteForm</code>، ثم ضع شيفرة إنشاء طرفة جديدة ضمنه.
</p>

<h3>
	6.8 طرائف: الخطوة 8
</h3>

<p>
	أنشئ مكوّنًا جديدًا وسمّه <code>AnecdoteList</code>، ثم انقل شيفرة تصيير قائمة الطرائف إليه.
</p>

<p>
	سيبدو محتوى المكوّن <code>App</code> الآن مشابهًا للتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1690_115" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">AnecdoteForm</span><span class="pln"> from </span><span class="str">'./components/AnecdoteForm'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">AnecdoteList</span><span class="pln"> from </span><span class="str">'./components/AnecdoteList'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="typ">Anecdotes</span><span class="pun">&lt;/</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">AnecdoteForm</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">AnecdoteList</span><span class="pln">  </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">App</span></pre>

<p>
	ترجمة -وبتصرف- للفصل <a data-ss1615732041="1" data-ss1615732607="1" href="https://fullstackopen.com/en/part6/flux_archeticture_and_redux" rel="external nofollow">Flux-architecture and Redux</a> من سلسلة <a data-ss1615732041="1" data-ss1615732607="1" href="https://fullstackopen.com/en/" rel="external nofollow">Deep Dive Into Modern Web Development</a>
</p>
]]></description><guid isPermaLink="false">1162</guid><pubDate>Thu, 11 Mar 2021 13:00:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x627;&#x62E;&#x62A;&#x628;&#x627;&#x631; &#x627;&#x644;&#x645;&#x634;&#x62A;&#x631;&#x643; &#x644;&#x644;&#x648;&#x627;&#x62C;&#x647;&#x62A;&#x64A;&#x646;: &#x627;&#x644;&#x623;&#x645;&#x627;&#x645;&#x64A;&#x629; React &#x648;&#x627;&#x644;&#x62E;&#x644;&#x641;&#x64A;&#x629; Node.js &#x639;&#x628;&#x631; &#x645;&#x643;&#x62A;&#x628;&#x629; Cypress</title><link>https://academy.hsoub.com/programming/javascript/react/%D8%A7%D9%84%D8%A7%D8%AE%D8%AA%D8%A8%D8%A7%D8%B1-%D8%A7%D9%84%D9%85%D8%B4%D8%AA%D8%B1%D9%83-%D9%84%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%AA%D9%8A%D9%86-%D8%A7%D9%84%D8%A3%D9%85%D8%A7%D9%85%D9%8A%D8%A9-react-%D9%88%D8%A7%D9%84%D8%AE%D9%84%D9%81%D9%8A%D8%A9-nodejs-%D8%B9%D8%A8%D8%B1-%D9%85%D9%83%D8%AA%D8%A8%D8%A9-cypress-r1139/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_02/602cdec712e39_--.png.a4bbf0c3ba9098760f85712236f7d2f3.png" /></p>

<p>
	اختبرنا حتى هذه اللحظة الواجهة الخلفية ككيان واحد على مستوى الواجهة البرمجية مستخدمين اختبارات التكامل. واختبرنا كذلك بعض مكوِّنات الواجهة الأمامية باستخدام اختبارات الأجزاء.
</p>

<p>
	سنلقي نظرة تاليًا على طريقة لاختبار <a data-ss1613553322="1" href="https://en.wikipedia.org/wiki/System_testing" rel="external nofollow">النظام ككل</a> باستخدام الاختبارات المشتركة للواجهتين (end to end).
</p>

<p>
	يمكننا تنفيذ الاختبارات المشتركة للواجهتين (E2E) لتطبيق الويب باستخدام متصفح ومكتبة اختبارات. وهناك العديد من المكتبات المتوفرة مثل <a data-ss1613553322="1" href="http://www.seleniumhq.org/" rel="external nofollow">Selenium</a> التي يمكن استخدامها مع كل المتصفحات تقريبًا. وكخيارٍ للمتصفحات، يمكن اعتماد المتصفحات الاختبارية (Headless Browsers)، وهي متصفحات لا تقدم واجهة تخاطب رسومية. يمكن للمتصفح Chrome أن يعمل كمتصفح اختباري مثلًا.
</p>

<p>
	وربما تكون اختبارات E2E هي الأكثر فائدة بين فئات الاختبارات، لأنها تختبر النظام من خلال الواجهة نفسها التي سيستعملها المستخدم الحقيقي.
</p>

<p>
	وبالطبع لهذه الاختبارات نقاط ضعفها. فتهيئة هذه الاختبارات يحمل الكثير من التحدي موازنة بالنوعين الآخرين. وقد تكون بطيئة أيضًا، فقد يتطلب تنفيذها إن كان النظام ضخمًا دقائق عدة وحتى ساعات. وهذا الأمر سيء أثناء التطوير، لأننا قد نضطر إلى استخدام الاختبارات بشكل متكرر وخاصة في حالات <a data-ss1613553322="1" href="https://en.wikipedia.org/wiki/Regression_testing" rel="external nofollow">انهيار</a> الشيفرة.
</p>

<p>
	والأسوء من ذلك كله أنها اختبارات <a data-ss1613553322="1" href="https://hackernoon.com/flaky-tests-a-war-that-never-ends-9aa32fdef359" rel="external nofollow">غير مستقرة</a> (flaky) فقد تنجح أحيانًا وتفشل في أخرى، على الرغم من عدم تغير الشيفرة.
</p>

<h2>
	Cypress: مكتبة الاختبارات المشتركة للواجهتين
</h2>

<p>
	ازدادت شعبية المكتبة Cypress في السنتين الماضيتين. وتتميز هذه المكتبة بالسهولة الكبيرة في الاستخدام، كما لن تعاني معها الكثير من الصداع و الانفعالات موازنة بغيرها من المكتبات مثل Selemium. وطريقة عمل هذه المكتبة مختلف جذريًا عن غيرها من مكتبات الاختبار E2E، لأن اختباراتها تعمل بشكل كامل على المتصفح. بينما تنفذ بقية المكتبات اختباراتها بعملية Node ترتبط بالمتصفح عبر واجهة برمجية.
</p>

<p>
	لنجر بعض اختبارات E2E على تطبيق الملاحظات، وسنبدأ بتثبيت المكتبة ضمن الواجهة الأمامية كاعتمادية تطوير:
</p>

<pre class="ipsCode">
npm install --save-dev cypress
</pre>

<p>
	و كذلك كتابة سكربت npm لتشغيل الاختبار:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_8" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
  </span><span class="str">"scripts"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"start"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"react-scripts start"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"build"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"react-scripts build"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"test"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"react-scripts test"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"eject"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"react-scripts eject"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"server"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"json-server -p3001 db.json"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"cypress:open"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"cypress open"</span><span class="pln">  </span><span class="pun">},</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وعلى خلاف اختبارات الأجزاء، يمكن أن تكون اختبارات Cypress في مستودع الواجهة الخلفية أو الأمامية أو في مستودعها الخاص. وتتطلب أن يكون النظام المختبر في حالة عمل، واختبارات Cypress على خلاف اختبارات تكامل الواجهة الخلفية لن تُشغِّل النظام عندما يبدأ تنفيذها.
</p>

<p>
	لنكتب سكربت npm للواجهة الخلفية بحيث تعمل في وضع الاختبار. أي تكون قيمة متغير البيئة <code>NODE_ENV</code> هي test:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_10" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
  </span><span class="str">"scripts"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"start"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"cross-env NODE_ENV=production node index.js"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"dev"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"cross-env NODE_ENV=development nodemon index.js"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"build:ui"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"rm -rf build &amp;&amp; cd ../../../2/luento/notes &amp;&amp; npm run build &amp;&amp; cp -r build ../../../3/luento/notes-backend"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"deploy"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"git push heroku master"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"deploy:full"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"npm run build:ui &amp;&amp; git add . &amp;&amp; git commit -m uibuild &amp;&amp; git push &amp;&amp; npm run deploy"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"logs:prod"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"heroku logs --tail"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"lint"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"eslint ."</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"test"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"cross-env NODE_ENV=test jest --verbose --runInBand"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"start:test"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"cross-env NODE_ENV=test node index.js"</span><span class="pln">  </span><span class="pun">},</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	عندما تبدأ الواجهتين الأمامية والخلفية بالعمل، يمكن تشغيل Cypress بتنفيذ الأمر:
</p>

<pre class="ipsCode">
npm run cypress:open
</pre>

<p>
	تُنشئ Cypress مجلدًا باسم "cypress". يضم هذا المجلد مجلدًا آخر باسم "integration" حيث سنضع اختباراتنا. كما تنشئ كمية من الاختبارات في المجلد "integration/examples". يمكننا حذف هذه الاختبارات وكتابة الاختبارات التي نريد في الملف note_app.spec.js:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_12" style="">
<span class="pln">describe</span><span class="pun">(</span><span class="str">'Note app'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  it</span><span class="pun">(</span><span class="str">'front page can be opened'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    cy</span><span class="pun">.</span><span class="pln">visit</span><span class="pun">(</span><span class="str">'http://localhost:3000'</span><span class="pun">)</span><span class="pln">
    cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'Notes'</span><span class="pun">)</span><span class="pln">
    cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'Note app, Department of Computer Science, University of Helsinki 2020'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	نبدأ الاختبار من النافذة المفتوحة التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-ss1613553322="1" href="https://academy.hsoub.com/uploads/monthly_2021_02/cypress_test_window_01.png.36df1abd29ce3e2af31e478e163cd9c4.png" data-fileid="57866" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="57866" data-unique="ies3hpyyh" src="https://academy.hsoub.com/uploads/monthly_2021_02/cypress_test_window_01.png.36df1abd29ce3e2af31e478e163cd9c4.png" alt="cypress_test_window_01.png"></a>
</p>

<p>
	يفتح تشغيل الاختبار المتصفح تلقائيًا، بحيث يعرض سلوك التطبيق أثناء الاختبار:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-ss1613553322="1" href="https://academy.hsoub.com/uploads/monthly_2021_02/browser_test_show_02.png.9efac586b2075d147b35373b0808d8d0.png" data-fileid="57862" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="57862" data-unique="75p193pw8" src="https://academy.hsoub.com/uploads/monthly_2021_02/browser_test_show_02.png.9efac586b2075d147b35373b0808d8d0.png" alt="browser_test_show_02.png"></a>
</p>

<p>
	من المفترض أن تكون بنية الاختبار مألوفة بالنسبة لك. فهي تستخدم كتلة الوصف (describe) لتجميع الاختبارات التي لها نفس الغاية كما تفعل Jest. تُعرَّف حالات الاختبارات باستخدام التابع <code>it</code>، حيث استعارت هذا الجزء من مكتبة الاختبارات <a data-ss1613553322="1" href="https://mochajs.org/" rel="external nofollow">Mocha</a> والذي تستخدمه تحت الستار.
</p>

<p>
	لاحظ أن <a data-ss1613553322="1" href="https://docs.cypress.io/api/commands/visit.html" rel="external nofollow">cy.visit</a> و<a data-ss1613553322="1" href="https://docs.cypress.io/api/commands/contains.html" rel="external nofollow">cy.contains</a> هما أمران عائدان للمكتبة Cypress والغرض منهما واضح للغاية. فالأمر <a data-ss1613553322="1" href="https://docs.cypress.io/api/commands/visit.html" rel="external nofollow">cy.visit</a> يفتح عنوان الويب الذي يمرر إليه كمعامل ضمن المتصفح، بينما يبحث الأمر <a data-ss1613553322="1" href="https://docs.cypress.io/api/commands/contains.html" rel="external nofollow">cy.contains</a> عن النص الذي يُمرر إليه كمعامل.
</p>

<p>
	يمكننا تعريف الاختبار باستعمال الدالة السهمية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_14" style="">
<span class="pln">describe</span><span class="pun">(</span><span class="str">'Note app'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  
    it</span><span class="pun">(</span><span class="str">'front page can be opened'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
    cy</span><span class="pun">.</span><span class="pln">visit</span><span class="pun">(</span><span class="str">'http://localhost:3000'</span><span class="pun">)</span><span class="pln">
    cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'Notes'</span><span class="pun">)</span><span class="pln">
    cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'Note app, Department of Computer Science, University of Helsinki 2020'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	<a data-ss1613553322="1" href="https://mochajs.org/#arrow-functions" rel="external nofollow">تُفضِّل</a> Mocha عدم استخدام الدوال السهمية لأنها تسبب بعض المشاكل في حالات خاصة.
</p>

<p>
	إن لم يعثر <code>cy.contains</code> على النص الذي يبحث عنه، سيفشل الاختبار. لذا لو وسعنا الاختبار كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_16" style="">
<span class="pln">describe</span><span class="pun">(</span><span class="str">'Note app'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  it</span><span class="pun">(</span><span class="str">'front page can be opened'</span><span class="pun">,</span><span class="pln">  </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    cy</span><span class="pun">.</span><span class="pln">visit</span><span class="pun">(</span><span class="str">'http://localhost:3000'</span><span class="pun">)</span><span class="pln">
    cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'Notes'</span><span class="pun">)</span><span class="pln">
    cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'Note app, Department of Computer Science, University of Helsinki 2020'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">

  it</span><span class="pun">(</span><span class="str">'front page contains random text'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">    
cy</span><span class="pun">.</span><span class="pln">visit</span><span class="pun">(</span><span class="str">'http://localhost:3000'</span><span class="pun">)</span><span class="pln">    
cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'wtf is this app?'</span><span class="pun">)</span><span class="pln">  </span><span class="pun">})})</span></pre>

<p>
	سيخفق الاختبار:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-ss1613553322="1" href="https://academy.hsoub.com/uploads/monthly_2021_02/cycontains_failed_03.png.8cbd85cf0f91d45d8efc833c45c2659e.png" data-fileid="57865" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="57865" data-unique="yqr3ha9gp" src="https://academy.hsoub.com/uploads/monthly_2021_02/cycontains_failed_03.png.8cbd85cf0f91d45d8efc833c45c2659e.png" alt="cycontains_failed_03.png"></a>
</p>

<p>
	لنُزِل الشيفرة التي أخفقت من الاختبار.
</p>

<h2>
	الكتابة في نموذج
</h2>

<p>
	لنوسع اختباراتنا بحيث يحاول الاختبار تسجيل الدخول إلى التطبيق. سنفترض هنا وجود مستخدم في الواجهة الخلفية باسم "mluukkai" وكلمة سره "Salainen". يبدأ الاختبار بفتح نموذج تسجيل الدخول.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_18" style="">
<span class="pln">describe</span><span class="pun">(</span><span class="str">'Note app'</span><span class="pun">,</span><span class="pln">  </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">

  it</span><span class="pun">(</span><span class="str">'login form can be opened'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    cy</span><span class="pun">.</span><span class="pln">visit</span><span class="pun">(</span><span class="str">'http://localhost:3000'</span><span class="pun">)</span><span class="pln">
    cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'login'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	يبحث الاختبار في البداية عن زر تسجيل الدخول من خلال النص الظاهر عليه مستخدمًا الأمر <a data-ss1613553322="1" href="https://docs.cypress.io/api/commands/click.html#Syntax" rel="external nofollow">cy.click</a>. يبدأ الاختباران بفتح الصفحة <a data-ss1613553322="1" href="http://localhost:3000/" rel="external nofollow">http://localhost:3000</a>، لذلك لابد من فصل الجزء المشترك في كتلة <code>beforeEach</code> قبل كل اختبار.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_20" style="">
<span class="pln">describe</span><span class="pun">(</span><span class="str">'Note app'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  beforeEach</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">    
      cy</span><span class="pun">.</span><span class="pln">visit</span><span class="pun">(</span><span class="str">'http://localhost:3000'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
  it</span><span class="pun">(</span><span class="str">'front page can be opened'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'Notes'</span><span class="pun">)</span><span class="pln">
    cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'Note app, Department of Computer Science, University of Helsinki 2020'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">

  it</span><span class="pun">(</span><span class="str">'login form can be opened'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'login'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	يحتوي حقل تسجيل الدخول على حقلين لإدخال النصوص، من المفترض أن يملأهما الاختبار. يسمح الأمر <a data-ss1613553322="1" href="https://docs.cypress.io/api/commands/get.html#Syntax" rel="external nofollow">cy.get</a> في البحث عن العناصر باستخدام مُحدِّد CSS. يمكننا الوصول إلى أول وآخر حقل إدخال نصي في الصفحة، ومن ثم الكتابة فيهما باستخدام الأمر <a data-ss1613553322="1" href="https://docs.cypress.io/api/commands/type.html#Syntax" rel="external nofollow">cy.type</a> كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_22" style="">
<span class="pln">it</span><span class="pun">(</span><span class="str">'user can login'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'login'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span><span class="pln">
  cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'input:first'</span><span class="pun">).</span><span class="pln">type</span><span class="pun">(</span><span class="str">'mluukkai'</span><span class="pun">)</span><span class="pln">
  cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'input:last'</span><span class="pun">).</span><span class="pln">type</span><span class="pun">(</span><span class="str">'salainen'</span><span class="pun">)})</span><span class="pln">  </span></pre>

<p>
	سيعمل التطبيق بشكل جيد، لكن المشاكل ستظهر إن قررنا لاحقًا إضافة حقول جديدة. ذلك أن الاختبار سيتوقع أن الحقول التي يجب ملؤها هما الحقلان الأول والأخير. لذا من الأفضل أن نعطي عناصر حقول الإدخال معرفات فريدة باستخدام الصفة <code>id</code>.
</p>

<p>
	سنغير في نموذج تسجيل الدخول قليلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_24" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">LoginForm</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> </span><span class="pun">...</span><span class="pln"> </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="typ">Login</span><span class="pun">&lt;/</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">form onSubmit</span><span class="pun">={</span><span class="pln">handleSubmit</span><span class="pun">}&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
          username
          </span><span class="pun">&lt;</span><span class="pln">input
            id</span><span class="pun">=</span><span class="str">'username'</span><span class="pln">            
            value</span><span class="pun">={</span><span class="pln">username</span><span class="pun">}</span><span class="pln">
            onChange</span><span class="pun">={</span><span class="pln">handleUsernameChange</span><span class="pun">}</span><span class="pln">
          </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
          password
          </span><span class="pun">&lt;</span><span class="pln">input
            id</span><span class="pun">=</span><span class="str">'password'</span><span class="pln">            
            type</span><span class="pun">=</span><span class="str">"password"</span><span class="pln">
            value</span><span class="pun">={</span><span class="pln">password</span><span class="pun">}</span><span class="pln">
            onChange</span><span class="pun">={</span><span class="pln">handlePasswordChange</span><span class="pun">}</span><span class="pln">
          </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">button id</span><span class="pun">=</span><span class="str">"login-button"</span><span class="pln"> type</span><span class="pun">=</span><span class="str">"submit"</span><span class="pun">&gt;</span><span class="pln">          
            login
        </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سنضيف أيضًا معرفات فريدة إلى زر الإرسال لكي نتمكن من الوصول إليه بمُعرِّفه.
</p>

<p>
	سيصبح الاختبار كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_26" style="">
<span class="pln">describe</span><span class="pun">(</span><span class="str">'Note app'</span><span class="pun">,</span><span class="pln">  </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ..</span><span class="pln">
  it</span><span class="pun">(</span><span class="str">'user can log in'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'login'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span><span class="pln">
    cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'#username'</span><span class="pun">).</span><span class="pln">type</span><span class="pun">(</span><span class="str">'mluukkai'</span><span class="pun">)</span><span class="pln"> 
    cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'#password'</span><span class="pun">).</span><span class="pln">type</span><span class="pun">(</span><span class="str">'salainen'</span><span class="pun">)</span><span class="pln">
    cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'#login-button'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span><span class="pln">
    cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'Matti Luukkainen logged in'</span><span class="pun">)</span><span class="pln">  
  </span><span class="pun">})</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	تتأكد الدالة السهمية بأن تسجيل الدخول سينجح.
</p>

<p>
	لاحظ أننا وضعنا (#) قبل اسم المستخدم وكلمة المرور عندما نريد البحث عنهما بالاستعانة بالمعرف id. ذلك أن <a data-ss1613553322="1" href="https://developer.mozilla.org/en-US/docs/Web/CSS/ID_selectors" rel="external nofollow">محدد التنسيق id</a> يستخدم الرمز (#).
</p>

<h2>
	بعض الأشياء التي يجدر ملاحظتها
</h2>

<p>
	ينقر الاختبار أولًا الزر الذي يفتح نموذج تسجيل الدخول:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_28" style="">
<span class="pln">cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'login'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span></pre>

<p>
	بعد أن تُملأ حقوله، يُرسل النموذج بالنقر على الزر submit:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_30" style="">
<span class="pln">cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'#login-button'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span></pre>

<p>
	يحمل كل من الزرين النص ذاته، لكنهما زران منفصلان. وكلاهما في الواقع موجود في نموذج DOM الخاص بالتطبيق، لكن أحدهما فقط سيظهر نظرًا لاستخدام التنسيق <code>display:None</code>.
</p>

<p>
	فلو بحثنا عن الزر باستخدام نصه، سيعيد الأمر <a data-ss1613553322="1" href="https://docs.cypress.io/api/commands/contains.html#Syntax" rel="external nofollow">cy.contains</a> الأول بينهما أو الزر الذي يفتح نموذج تسجيل الدخول. وسيحدث هذا حتى لو لم يكن الزر مرئيًا. لتفادي المشكلة الناتجة عن تضارب الأسماء، أعطينا زر الإرسال الاسم "login-button".
</p>

<p>
	سنلاحظ مباشرة الخطأ الذي يعطيه المدقق ESlint حول المتغير <code>cy</code> الذي نستخدمه:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-ss1613553322="1" href="https://academy.hsoub.com/uploads/monthly_2021_02/cy_lint_error_04.png.517fddbc43fd778ea0fc47819e80097f.png" data-fileid="57864" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="57864" data-unique="3oy5i9zav" src="https://academy.hsoub.com/uploads/monthly_2021_02/cy_lint_error_04.png.517fddbc43fd778ea0fc47819e80097f.png" alt="cy_lint_error_04.png"></a>
</p>

<p>
	يمكن التخلص من هذا الخطأ بتثبيت المكتبة <a data-ss1613553322="1" href="https://github.com/cypress-io/eslint-plugin-cypress" rel="external nofollow">eslint-plugin-cypress</a> كاعتمادية تطوير:
</p>

<pre class="ipsCode">
npm install eslint-plugin-cypress --save-dev
</pre>

<p>
	كما علينا تغيير إعدادات التهيئة في الملف eslintrc.js كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_32" style="">
<span class="pln">module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"env"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="str">"browser"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
        </span><span class="str">"es6"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
        </span><span class="str">"jest/globals"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
        </span><span class="str">"cypress/globals"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">    </span><span class="pun">},</span><span class="pln">
    </span><span class="str">"extends"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> 
      </span><span class="com">// ...</span><span class="pln">
    </span><span class="pun">],</span><span class="pln">
    </span><span class="str">"parserOptions"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="com">// ...</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    </span><span class="str">"plugins"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
        </span><span class="str">"react"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"jest"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"cypress"</span><span class="pln">    </span><span class="pun">],</span><span class="pln">
    </span><span class="str">"rules"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="com">// ...</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	اختبار نموذج إنشاء ملاحظة جديدة
</h2>

<p>
	لنضف الآن اختبارًا لإنشاء ملاحظة جديدة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_34" style="">
<span class="pln">describe</span><span class="pun">(</span><span class="str">'Note app'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ..</span><span class="pln">
  describe</span><span class="pun">(</span><span class="str">'when logged in'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      beforeEach</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'login'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span><span class="pln">
          cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'input:first'</span><span class="pun">).</span><span class="pln">type</span><span class="pun">(</span><span class="str">'mluukkai'</span><span class="pun">)</span><span class="pln">
          cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'input:last'</span><span class="pun">).</span><span class="pln">type</span><span class="pun">(</span><span class="str">'salainen'</span><span class="pun">)</span><span class="pln">      
          cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'#login-button'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span><span class="pln">    
      </span><span class="pun">})</span><span class="pln">
    it</span><span class="pun">(</span><span class="str">'a new note can be created'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">      
        cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'new note'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span><span class="pln">      
        cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'input'</span><span class="pun">).</span><span class="pln">type</span><span class="pun">(</span><span class="str">'a note created by cypress'</span><span class="pun">)</span><span class="pln">
        cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'save'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span><span class="pln">      
        cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'a note created by cypress'</span><span class="pun">)</span><span class="pln">    
    </span><span class="pun">})</span><span class="pln">  
  </span><span class="pun">})})</span></pre>

<p>
	عُرِّف الاختبار ضمن كتلة وصف خاص به. يمكن فقط للمستخدمين المسجلين إضافة ملاحظة جديدة، لذلك أضفنا تسجيل الدخول إلى كتلة <code>beforeEach</code>.
</p>

<p>
	يتوقع الاختبار وجود حقل نصي واحد لإدخال البيانات في الصفحة، لذا سيبحث عنه كالتالي:
</p>

<pre class="ipsCode">
cy.get('input')
</pre>

<p>
	سيفشل الاختبار في حال احتوت الصفحة على أكثر من عنصر إدخال:
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="57869" data-unique="g4edx2w9y" src="https://academy.hsoub.com/uploads/monthly_2021_02/many_inputs_fail_05.png.3e5f47f7df9e10e029066446f2f3cd56.png" alt="many_inputs_fail_05.png"></p>

<p>
	لذلك من الأفضل إعطاء عنصر الإدخال معرِّف فريد خاص به والبحث عن العنصر باستخدام معرِّفه.
</p>

<p>
	ستبدو بنية الاختبار كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_36" style="">
<span class="pln">describe</span><span class="pun">(</span><span class="str">'Note app'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">

  it</span><span class="pun">(</span><span class="str">'user can log in'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'login'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span><span class="pln">
    cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'#username'</span><span class="pun">).</span><span class="pln">type</span><span class="pun">(</span><span class="str">'mluukkai'</span><span class="pun">)</span><span class="pln">
    cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'#password'</span><span class="pun">).</span><span class="pln">type</span><span class="pun">(</span><span class="str">'salainen'</span><span class="pun">)</span><span class="pln">
    cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'#login-button'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span><span class="pln">

    cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'Matti Luukkainen logged in'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">

  describe</span><span class="pun">(</span><span class="str">'when logged in'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    beforeEach</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'login'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span><span class="pln">
      cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'input:first'</span><span class="pun">).</span><span class="pln">type</span><span class="pun">(</span><span class="str">'mluukkai'</span><span class="pun">)</span><span class="pln">
      cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'input:last'</span><span class="pun">).</span><span class="pln">type</span><span class="pun">(</span><span class="str">'salainen'</span><span class="pun">)</span><span class="pln">
      cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'#login-button'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">

    it</span><span class="pun">(</span><span class="str">'a new note can be created'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="com">// ...</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	ستُنفِّذ Cypress الاختبارات وفق ترتيب ظهورها في الشيفرة. ففي البداية ستنفذ المكتبة الاختبار الذي يحمل العنوان "user can log in" حيث سيسجل المستخدم دخوله. وبعدها ستُنفّذ المكتبة الاختبار الذي يحمل العنوان "a new note can be created" والذي سيجعل كتلة <code>beforeEach</code> تُجري تسجيل دخول جديد.
</p>

<p>
	لم حدث ذلك طالما أننا سجلنا الدخول أول مرة؟ السبب أن كل اختبار سيبدأ من نقطة الصفر طالما أن المتصفح يتطلب ذلك. وسيعود المتصفح إلى حالته الأصلية بعد انتهاء الاختبار.
</p>

<h2>
	التحكم بحالة قاعدة البيانات
</h2>

<p>
	ستغدو الأمور أكثر تعقيدًا عندما يحاول الاختبار إجراء تغييرات على قاعدة بيانات الخادم. إذ ينبغي على قاعدة البيانات أن تبقى كما هي في كل مرة نجري فيها الاختبار، وذلك لتبقى الاختبارات مفيدة و سهلة التكرار. وكما هي حال اختباري الأجزاء والتكامل، تتطلب اختبارات E2E إفراغ قاعدة البيانات أو حتى إعادة تنسيقها أحيانًا قبل كل اختبار. إن التحدي مع هذا النوع من الاختبارات أنها لا تستطيع الولوج إلى قاعدة البيانات. لحل هذه المشكلة لابد من من استخدام طرفيات خدمية على الواجهة الخلفية ترتبط بها الواجهة البرمجية من أجل الاختبار. إذ يمكننا إفراغ قاعدة البيانات باستخدام تلك الطرفيات مثلًا. لننشئ الآن متحكمًا بالمسار لهذه الاختبارات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_38" style="">
<span class="kwd">const</span><span class="pln"> router </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'express'</span><span class="pun">).</span><span class="typ">Router</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Note</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'../models/note'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">User</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'../models/user'</span><span class="pun">)</span><span class="pln">

router</span><span class="pun">.</span><span class="pln">post</span><span class="pun">(</span><span class="str">'/reset'</span><span class="pun">,</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">request</span><span class="pun">,</span><span class="pln"> response</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  await </span><span class="typ">Note</span><span class="pun">.</span><span class="pln">deleteMany</span><span class="pun">({})</span><span class="pln">
  await </span><span class="typ">User</span><span class="pun">.</span><span class="pln">deleteMany</span><span class="pun">({})</span><span class="pln">

  response</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">204</span><span class="pun">).</span><span class="pln">end</span><span class="pun">()</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> router</span></pre>

<p>
	سنضيف المتحكم إلى الواجهة الخلفية عندما يعمل التطبيق في وضع الاختبار فقط:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_40" style="">
<span class="com">// ...</span><span class="pln">

app</span><span class="pun">.</span><span class="pln">use</span><span class="pun">(</span><span class="str">'/api/login'</span><span class="pun">,</span><span class="pln"> loginRouter</span><span class="pun">)</span><span class="pln">
app</span><span class="pun">.</span><span class="pln">use</span><span class="pun">(</span><span class="str">'/api/users'</span><span class="pun">,</span><span class="pln"> usersRouter</span><span class="pun">)</span><span class="pln">
app</span><span class="pun">.</span><span class="pln">use</span><span class="pun">(</span><span class="str">'/api/notes'</span><span class="pun">,</span><span class="pln"> notesRouter</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">process</span><span class="pun">.</span><span class="pln">env</span><span class="pun">.</span><span class="pln">NODE_ENV </span><span class="pun">===</span><span class="pln"> </span><span class="str">'test'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  </span><span class="kwd">const</span><span class="pln"> testingRouter </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'./controllers/testing'</span><span class="pun">)</span><span class="pln">  app</span><span class="pun">.</span><span class="pln">use</span><span class="pun">(</span><span class="str">'/api/testing'</span><span class="pun">,</span><span class="pln"> testingRouter</span><span class="pun">)}</span><span class="pln">
app</span><span class="pun">.</span><span class="pln">use</span><span class="pun">(</span><span class="pln">middleware</span><span class="pun">.</span><span class="pln">unknownEndpoint</span><span class="pun">)</span><span class="pln">
app</span><span class="pun">.</span><span class="pln">use</span><span class="pun">(</span><span class="pln">middleware</span><span class="pun">.</span><span class="pln">errorHandler</span><span class="pun">)</span><span class="pln">

module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> app</span></pre>

<p>
	بعد إجراء التغييرات، يُرسل طلب HTTP-POST إلى الطرفية api/testing/reset/ لتفريغ قاعدة البيانات.
</p>

<p>
	يمكنك إيجاد شيفرة الواجهة الخلفية المعدلّة في الفرع part5-1 ضمن المستودع الخاص بالتطبيق على <a data-ss1613553322="1" href="https://github.com/fullstack-hy2020/part3-notes-backend/tree/part5-1" rel="external nofollow">GitHub</a>.
</p>

<p>
	سنغير تاليًا كتلة <code>beforeEach</code> بحيث تفرّغ قاعدة البيانات قبل أن تبدأ الاختبارات. لا نستطيع حاليًا إضافة مستخدم جديد من خلال الواجهة الأمامية، لذلك سنضيف مستخدم جديد إلى الواجهة الخلفية من خلال الكتلة <code>beforeEach</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_42" style="">
<span class="pln">describe</span><span class="pun">(</span><span class="str">'Note app'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   beforeEach</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    cy</span><span class="pun">.</span><span class="pln">request</span><span class="pun">(</span><span class="str">'POST'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'http://localhost:3001/api/testing/reset'</span><span class="pun">)</span><span class="pln">    
       </span><span class="kwd">const</span><span class="pln"> user </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">      
           name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Matti Luukkainen'</span><span class="pun">,</span><span class="pln">      
           username</span><span class="pun">:</span><span class="pln"> </span><span class="str">'mluukkai'</span><span class="pun">,</span><span class="pln">      
           password</span><span class="pun">:</span><span class="pln"> </span><span class="str">'salainen'</span><span class="pln">    
       </span><span class="pun">}</span><span class="pln">    
       cy</span><span class="pun">.</span><span class="pln">request</span><span class="pun">(</span><span class="str">'POST'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'http://localhost:3001/api/users/'</span><span class="pun">,</span><span class="pln"> user</span><span class="pun">)</span><span class="pln">     
       cy</span><span class="pun">.</span><span class="pln">visit</span><span class="pun">(</span><span class="str">'http://localhost:3000'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">

  it</span><span class="pun">(</span><span class="str">'front page can be opened'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ...</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">

  it</span><span class="pun">(</span><span class="str">'user can login'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ...</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">

  describe</span><span class="pun">(</span><span class="str">'when logged in'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ...</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	أثناء إعادة التنسيق يرسل الاختبار طلب HTTP إلى الواجهة الخلفية باستخدام <a data-ss1613553322="1" href="https://docs.cypress.io/api/commands/request.html" rel="external nofollow">cy.request</a>. وعلى عكس ما حصل سابقًا، سيبدأ الاختبار الآن عند الواجهة الخلفية وبنفس الحالة كل مرة. حيث ستحتوي على مستخدم واحد وبدون أية ملاحظات.
</p>

<p>
	لنضف اختبارًا آخر نتحقق فيه من إمكانية تغير أهمية الملاحظة. سنغيّر أولًا الواجهة الأمامية بحيث تكون الملاحظة غير مهمة افتراضيًا. أو أن الحقل "importance" يحوي القيمة (خاطئ- false).
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_44" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">NoteForm</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> createNote </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> addNote </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">
    createNote</span><span class="pun">({</span><span class="pln">
      content</span><span class="pun">:</span><span class="pln"> newNote</span><span class="pun">,</span><span class="pln">
      important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">    </span><span class="pun">})</span><span class="pln">

    setNewNote</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span></pre>

<p>
	هناك طرق عدة لاختبار ذلك. نبحث في المثال التالي عن ملاحظة ونضغط على الزر المجاور لها "make importnant". ونتحقق بعد ذلك من احتواء الملاحظة لهذا الزر.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_46" style="">
<span class="pln">describe</span><span class="pun">(</span><span class="str">'Note app'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">

  describe</span><span class="pun">(</span><span class="str">'when logged in'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ...</span><span class="pln">

    describe</span><span class="pun">(</span><span class="str">'and a note exists'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      beforeEach</span><span class="pun">(</span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'new note'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span><span class="pln">
        cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'input'</span><span class="pun">).</span><span class="pln">type</span><span class="pun">(</span><span class="str">'another note cypress'</span><span class="pun">)</span><span class="pln">
        cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'save'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span><span class="pln">
      </span><span class="pun">})</span><span class="pln">

      it</span><span class="pun">(</span><span class="str">'it can be made important'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'another note cypress'</span><span class="pun">)</span><span class="pln">
          </span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'make important'</span><span class="pun">)</span><span class="pln">
          </span><span class="pun">.</span><span class="pln">click</span><span class="pun">()</span><span class="pln">

        cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'another note cypress'</span><span class="pun">)</span><span class="pln">
          </span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'make not important'</span><span class="pun">)</span><span class="pln">
      </span><span class="pun">})</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	يبحث الأمر الأول عن المكوِّن الذي يحتوي النص "another note cypress"، ثم عن الزر "make important" ضمنه. بعد ذلك ينقر على هذا الزر. يتحقق الأمر الثاني أن النص على الزر قد تغير إلى "make not important".
</p>

<p>
	يمكن إيجاد الاختبار والشيفرة الحالية للواجهة الأمامية ضمن الفرع part5-9 في المستودع المخصص للتطبيق على <a data-ss1613553322="1" href="https://github.com/fullstack-hy2020/part2-notes/tree/part5-9" rel="external nofollow">GitHub</a>.
</p>

<h2>
	اختبار إخفاق تسجيل الدخول
</h2>

<p>
	لنكتب اختبارًا يتحقق من فشل تسجيل الدخول عندما تكون كلمة المرور خاطئة.
</p>

<p>
	ستنفذ Cypress كل الاختبارات الموجودة بشكل افتراضي، وطالما أن عدد الاختبارات في ازدياد، سيؤدي ذلك إلى زيادة وقت التنفيذ. لذلك عندما نطور اختبارًا جديدًا أو نحاول إصلاح اختبار، من الأفضل تحديد هذا الاختبار فقط ليُنفّذ وذلك باستخدام الأمر <code>it.only</code>. ويمكننا بعدها إزالة الكلمة <code>only</code> عند نجاح الاختبار.
</p>

<p>
	ستبدو النسخة الأولى من الاختبار كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_48" style="">
<span class="pln">describe</span><span class="pun">(</span><span class="str">'Note app'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">

  it</span><span class="pun">.</span><span class="pln">only</span><span class="pun">(</span><span class="str">'login fails with wrong password'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'login'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span><span class="pln">
    cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'#username'</span><span class="pun">).</span><span class="pln">type</span><span class="pun">(</span><span class="str">'mluukkai'</span><span class="pun">)</span><span class="pln">
    cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'#password'</span><span class="pun">).</span><span class="pln">type</span><span class="pun">(</span><span class="str">'wrong'</span><span class="pun">)</span><span class="pln">
    cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'#login-button'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span><span class="pln">

    cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'wrong credentials'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">

  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">)}</span></pre>

<p>
	يستخدم الاختبار الأمر <a data-ss1613553322="1" href="https://docs.cypress.io/api/commands/contains.html#Syntax" rel="external nofollow">cy.contains</a> للتأكد من أن التطبيق سيطبع رسالة خطأ. سيصيّر التطبيق رسالة الخطأ إلى مكوِّن يمتلك صنف تنسيق CSS اسمه "error":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_50" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Notification</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> message </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">message </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">null</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div className</span><span class="pun">=</span><span class="str">"error"</span><span class="pun">&gt;</span><span class="pln">      
      </span><span class="pun">{</span><span class="pln">message</span><span class="pun">}</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يمكننا أن نجعل الاختبار يتحقق من أن رسالة الخطأ قد صُيِّرت إلى المكوِّن الصحيح الذي يمتلك صنف CSS باسم "error".
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_52" style="">
<span class="pln">it</span><span class="pun">(</span><span class="str">'login fails with wrong password'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">

  cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'.error'</span><span class="pun">).</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'wrong credentials'</span><span class="pun">)})</span></pre>

<p>
	نستخدم أولًا <a data-ss1613553322="1" href="https://docs.cypress.io/api/commands/get.html#Syntax" rel="external nofollow">cy.get</a> للبحث عن المكوّن الذي يمتلك صنف التنسيق "error". بعد ذلك نتحقق أن رسالة الخطأ موجودة ضمن هذا المكوِّن. وانتبه إلى استعمال العبارة 'error.' كمعامل للتابع <code>cy.get</code> ذلك أن <a data-ss1613553322="1" href="https://developer.mozilla.org/en-US/docs/Web/CSS/Class_selectors" rel="external nofollow">محدد الأصناف</a> في تنسيق CSS يبدأ بالمحرف (.).
</p>

<p>
	كما يمكن تنفيذ ذلك باستخدام العبارة <a data-ss1613553322="1" href="https://docs.cypress.io/api/commands/should.html" rel="external nofollow">should</a>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_54" style="">
<span class="pln">it</span><span class="pun">(</span><span class="str">'login fails with wrong password'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">

  cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'.error'</span><span class="pun">).</span><span class="pln">should</span><span class="pun">(</span><span class="str">'contain'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'wrong credentials'</span><span class="pun">)})</span></pre>

<p>
	على الرغم من أن استعمال <code>should</code> أكثر غموضًا من استخدام <code>contains</code>. لكنها تسمح باختبارات أكثر تنوعًا معتمدةً على المحتوى النصي فقط.
</p>

<p>
	يمكنك الاطلاع ضمن مستندات المكتبة Cypress على <a data-ss1613553322="1" href="ttps://docs.cypress.io/guides/references/assertions.html#Common-Assertions" rel="external nofollow">أكثر المفاتيح استخدامًا</a> مع <code>should</code>.
</p>

<p>
	يمكننا أن نتحقق مثلًا من أن رسالة الخطأ ستظهر باللون الأحمر ومحاطة بإطار:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_56" style="">
<span class="pln">it</span><span class="pun">(</span><span class="str">'login fails with wrong password'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">

  cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'.error'</span><span class="pun">).</span><span class="pln">should</span><span class="pun">(</span><span class="str">'contain'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'wrong credentials'</span><span class="pun">)</span><span class="pln"> 
  cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'.error'</span><span class="pun">).</span><span class="pln">should</span><span class="pun">(</span><span class="str">'have.css'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'color'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'rgb(255, 0, 0)'</span><span class="pun">)</span><span class="pln">
  cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'.error'</span><span class="pun">).</span><span class="pln">should</span><span class="pun">(</span><span class="str">'have.css'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'border-style'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'solid'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	تتطلب Cypress أن تُعطى الألوان بطريقة <a data-ss1613553322="1" href="https://rgbcolorcode.com/color/red" rel="external nofollow">rgb</a>.
</p>

<p>
	وطالما أن جميع الاختبارات ستجري على المكوِّن نفسه باستخدام <a data-ss1613553322="1" href="https://docs.cypress.io/api/commands/get.html#Syntax" rel="external nofollow">cy.get</a> سنسلسل الاختبارات باستخدام <a data-ss1613553322="1" href="https://docs.cypress.io/api/commands/and.html" rel="external nofollow">and</a>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_58" style="">
<span class="pln">it</span><span class="pun">(</span><span class="str">'login fails with wrong password'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">

  cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'.error'</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">.</span><span class="pln">should</span><span class="pun">(</span><span class="str">'contain'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'wrong credentials'</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">.</span><span class="pln">and</span><span class="pun">(</span><span class="str">'have.css'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'color'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'rgb(255, 0, 0)'</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">.</span><span class="pln">and</span><span class="pun">(</span><span class="str">'have.css'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'border-style'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'solid'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	لننهي الاختبار بحيث يتحقق أخيرًا أن التطبيق لن يصيّر رسالة النجاح "Matti Luukkainen logged in":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_60" style="">
<span class="pln">it</span><span class="pun">.</span><span class="pln">only</span><span class="pun">(</span><span class="str">'login fails with wrong password'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'login'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span><span class="pln">
  cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'#username'</span><span class="pun">).</span><span class="pln">type</span><span class="pun">(</span><span class="str">'mluukkai'</span><span class="pun">)</span><span class="pln">
  cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'#password'</span><span class="pun">).</span><span class="pln">type</span><span class="pun">(</span><span class="str">'wrong'</span><span class="pun">)</span><span class="pln">
  cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'#login-button'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span><span class="pln">

  cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'.error'</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">.</span><span class="pln">should</span><span class="pun">(</span><span class="str">'contain'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'wrong credentials'</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">.</span><span class="pln">and</span><span class="pun">(</span><span class="str">'have.css'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'color'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'rgb(255, 0, 0)'</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">.</span><span class="pln">and</span><span class="pun">(</span><span class="str">'have.css'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'border-style'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'solid'</span><span class="pun">)</span><span class="pln">

  cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'html'</span><span class="pun">).</span><span class="pln">should</span><span class="pun">(</span><span class="str">'not.contain'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Matti Luukkainen logged in'</span><span class="pun">)})</span></pre>

<p>
	لا ينبغي أن تُقيد الأمر <code>should</code> دائمًا بسلسلة <code>get</code> (أو أية تعليمات قابلة للتسلسل). كما يمكن استخدام الأمر <code>('cy.get('html</code> للوصول إلى كامل محتويات التطبيق المرئية.
</p>

<h2>
	تجاوز واجهة المستخدم UI
</h2>

<p>
	كتبنا حتى اللحظة الاختبارات التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_62" style="">
<span class="pln">describe</span><span class="pun">(</span><span class="str">'Note app'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  it</span><span class="pun">(</span><span class="str">'user can login'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'login'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span><span class="pln">
    cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'#username'</span><span class="pun">).</span><span class="pln">type</span><span class="pun">(</span><span class="str">'mluukkai'</span><span class="pun">)</span><span class="pln">
    cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'#password'</span><span class="pun">).</span><span class="pln">type</span><span class="pun">(</span><span class="str">'salainen'</span><span class="pun">)</span><span class="pln">
    cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'#login-button'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span><span class="pln">

    cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'Matti Luukkainen logged in'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">

  it</span><span class="pun">.</span><span class="pln">only</span><span class="pun">(</span><span class="str">'login fails with wrong password'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ...</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">

  describe</span><span class="pun">(</span><span class="str">'when logged in'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    beforeEach</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'login'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span><span class="pln">
      cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'input:first'</span><span class="pun">).</span><span class="pln">type</span><span class="pun">(</span><span class="str">'mluukkai'</span><span class="pun">)</span><span class="pln">
      cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'input:last'</span><span class="pun">).</span><span class="pln">type</span><span class="pun">(</span><span class="str">'salainen'</span><span class="pun">)</span><span class="pln">
      cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'#login-button'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">

    it</span><span class="pun">(</span><span class="str">'a new note can be created'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="com">// ... </span><span class="pln">
    </span><span class="pun">})</span><span class="pln">

  </span><span class="pun">})</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	اختبرنا بداية تسجيل الدخول. ومن ثم رأينا جملة من الاختبارات الموجودة في كتلة وصف خاصة تتوقع من المستخدم أن يسجل دخوله والذي سيحدث ضمن الكتلة <code>beforeEach</code>.
</p>

<p>
	وكما قلنا سابقًا: سيبدأ كل اختبار من الصفر، فلا تبدأ الاختبار أبدًا من حيث ينتهي الاختبار الذي يسبقه.
</p>

<p>
	يقدم لنا توثيق Cypress النصيحة التالية: <a data-ss1613553322="1" href="https://docs.cypress.io/guides/getting-started/testing-your-app.html#Logging-in" rel="external nofollow">اختبر ثغرات تسجيل الدخول بشكل كامل- لكن لمرة واحدة!</a>. لذا وبدلًا من تسجيل الدخول باستخدام نموذج تسجيل الدخول الموجود في كتلة الاختبارات <code>beforeEach</code>، تنصحنا Cypress <a data-ss1613553322="1" href="https://docs.cypress.io/guides/getting-started/testing-your-app.html#Bypassing-your-UI" rel="external nofollow">بتجاوز واجهة المستخدم</a> و إرسال طلب HTTP إلى الواجهة الخلفية لتسجيل الدخول. وذلك لأن تسجيل الدخول باستخدام طلب HTTP أسرع بكثير من ملئ النموذج وإرساله.
</p>

<p>
	لكن وضع تطبيقنا أعقد قليلًا من المثال الذي أورده توثيق Cypress، لأن التطبيق سيخزن تفاصيل المستخدم عند تسجيل الدخول في الذاكرة المحلية. مع ذلك تستطيع Cypress التعامل مع هذا الوضع كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_64" style="">
<span class="pln">describe</span><span class="pun">(</span><span class="str">'when logged in'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  beforeEach</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    cy</span><span class="pun">.</span><span class="pln">request</span><span class="pun">(</span><span class="str">'POST'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'http://localhost:3001/api/login'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">      
        username</span><span class="pun">:</span><span class="pln"> </span><span class="str">'mluukkai'</span><span class="pun">,</span><span class="pln"> password</span><span class="pun">:</span><span class="pln"> </span><span class="str">'salainen'</span><span class="pln">    
    </span><span class="pun">}).</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">      
        localStorage</span><span class="pun">.</span><span class="pln">setItem</span><span class="pun">(</span><span class="str">'loggedNoteappUser'</span><span class="pun">,</span><span class="pln"> 
                              JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">(</span><span class="pln">response</span><span class="pun">.</span><span class="pln">body</span><span class="pun">))</span><span class="pln">      
        cy</span><span class="pun">.</span><span class="pln">visit</span><span class="pun">(</span><span class="str">'http://localhost:3000'</span><span class="pun">)</span><span class="pln">    </span><span class="pun">})</span><span class="pln">  </span><span class="pun">})</span><span class="pln">

  it</span><span class="pun">(</span><span class="str">'a new note can be created'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ...</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">

  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	يمكننا الوصول إلى استجابة الطلب <a data-ss1613553322="1" href="https://docs.cypress.io/api/commands/request.html" rel="external nofollow">cy.request</a> باستخدام التابع <code>then</code>. سنجد في جوار <code>cy.request</code> <a data-ss1613553322="1" href="https://docs.cypress.io/guides/core-concepts/introduction-to-cypress.html#Commands-Are-Promises" rel="external nofollow">وعدًا</a> كغيره من أوامر Cypress. تخزّن دالة الاستدعاء تفاصيل تسجيل الدخول في الذاكرة المحلية، ثم تعيد تحميل الصفحة.
</p>

<p>
	لا أهمية الآن لدخول المستخدم من خلال نموذج تسجيل الدخول في أي اختبار سنجريه على التطبيق، إذ سنستخدم شيفرة تسجيل الدخول في المكان الذي نحتاجه. وعلينا أن نجعل تسجيل الدخول <a data-ss1613553322="1" href="https://docs.cypress.io/api/cypress-api/custom-commands.htm" rel="external nofollow">كأمر خاص بالمستخدم</a>. يُصرّح عن أوامر المستخدم الخاصة في الملف commands.js ضمن المجلد cypress/support. ستبدو شيفرة تسجيل الدخول كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_66" style="">
<span class="typ">Cypress</span><span class="pun">.</span><span class="typ">Commands</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="str">'login'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> username</span><span class="pun">,</span><span class="pln"> password </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  cy</span><span class="pun">.</span><span class="pln">request</span><span class="pun">(</span><span class="str">'POST'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'http://localhost:3001/api/login'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    username</span><span class="pun">,</span><span class="pln"> password
  </span><span class="pun">}).</span><span class="pln">then</span><span class="pun">(({</span><span class="pln"> body </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    localStorage</span><span class="pun">.</span><span class="pln">setItem</span><span class="pun">(</span><span class="str">'loggedNoteappUser'</span><span class="pun">,</span><span class="pln"> JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">(</span><span class="pln">body</span><span class="pun">))</span><span class="pln">
    cy</span><span class="pun">.</span><span class="pln">visit</span><span class="pun">(</span><span class="str">'http://localhost:3000'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	سيكون استخدام الأمر الخاص بنا سهلًا، وستغدو الاختبارات أكثر وضوحًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_68" style="">
<span class="pln">describe</span><span class="pun">(</span><span class="str">'when logged in'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  beforeEach</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    cy</span><span class="pun">.</span><span class="pln">login</span><span class="pun">({</span><span class="pln"> username</span><span class="pun">:</span><span class="pln"> </span><span class="str">'mluukkai'</span><span class="pun">,</span><span class="pln"> password</span><span class="pun">:</span><span class="pln"> </span><span class="str">'salainen'</span><span class="pln"> </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">

  it</span><span class="pun">(</span><span class="str">'a new note can be created'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ...</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">

  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	ينطبق ذلك تمامًا على إنشاء ملاحظة جديدة. لدينا اختبار إنشاء ملاحظة جديدة باستخدام النموذج. كما سننشئ ملاحظة جديدة ضمن كتلة <code>beforeEach</code> والتي سنختبر من خلالها تغيّر أهمية الملاحظة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_70" style="">
<span class="pln">describe</span><span class="pun">(</span><span class="str">'Note app'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">

  describe</span><span class="pun">(</span><span class="str">'when logged in'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    it</span><span class="pun">(</span><span class="str">'a new note can be created'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'new note'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span><span class="pln">
      cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'input'</span><span class="pun">).</span><span class="pln">type</span><span class="pun">(</span><span class="str">'a note created by cypress'</span><span class="pun">)</span><span class="pln">
      cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'save'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span><span class="pln">

      cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'a note created by cypress'</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">

    describe</span><span class="pun">(</span><span class="str">'and a note exists'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      beforeEach</span><span class="pun">(</span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'new note'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span><span class="pln">
        cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'input'</span><span class="pun">).</span><span class="pln">type</span><span class="pun">(</span><span class="str">'another note cypress'</span><span class="pun">)</span><span class="pln">
        cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'save'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span><span class="pln">
      </span><span class="pun">})</span><span class="pln">

      it</span><span class="pun">(</span><span class="str">'it can be made important'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="com">// ...</span><span class="pln">
      </span><span class="pun">})</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	لنكتب أمرًا خاصًا بالمستخدم لإنشاء ملاحظة جديدة عبر طلب HTTP-POST:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_72" style="">
<span class="typ">Cypress</span><span class="pun">.</span><span class="typ">Commands</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="str">'createNote'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> content</span><span class="pun">,</span><span class="pln"> important </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  cy</span><span class="pun">.</span><span class="pln">request</span><span class="pun">({</span><span class="pln">
    url</span><span class="pun">:</span><span class="pln"> </span><span class="str">'http://localhost:3001/api/notes'</span><span class="pun">,</span><span class="pln">
    method</span><span class="pun">:</span><span class="pln"> </span><span class="str">'POST'</span><span class="pun">,</span><span class="pln">
    body</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> content</span><span class="pun">,</span><span class="pln"> important </span><span class="pun">},</span><span class="pln">
    headers</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="str">'Authorization'</span><span class="pun">:</span><span class="pln"> </span><span class="pun">`</span><span class="pln">bearer $</span><span class="pun">{</span><span class="pln">JSON</span><span class="pun">.</span><span class="pln">parse</span><span class="pun">(</span><span class="pln">localStorage</span><span class="pun">.</span><span class="pln">getItem</span><span class="pun">(</span><span class="str">'loggedNoteappUser'</span><span class="pun">)).</span><span class="pln">token</span><span class="pun">}`</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">

  cy</span><span class="pun">.</span><span class="pln">visit</span><span class="pun">(</span><span class="str">'http://localhost:3000'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	يتوقع الأمر أن يسجل المستخدم دخوله، وأن تُخزّن التفاصيل في الذاكرة المحلية.
</p>

<p>
	ستصبح الآن كتلة التنسيق كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_74" style="">
<span class="pln">describe</span><span class="pun">(</span><span class="str">'Note app'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">

  describe</span><span class="pun">(</span><span class="str">'when logged in'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    it</span><span class="pun">(</span><span class="str">'a new note can be created'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="com">// ...</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">

    describe</span><span class="pun">(</span><span class="str">'and a note exists'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      beforeEach</span><span class="pun">(</span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        cy</span><span class="pun">.</span><span class="pln">createNote</span><span class="pun">({</span><span class="pln">          
            content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'another note cypress'</span><span class="pun">,</span><span class="pln">          
            important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">        
        </span><span class="pun">})</span><span class="pln">      
      </span><span class="pun">})</span><span class="pln">

      it</span><span class="pun">(</span><span class="str">'it can be made important'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="com">// ...</span><span class="pln">
      </span><span class="pun">})</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	ستجد الاختبارات و شيفرة الواجهة الأمامية ضمن الفرع part5-10 في المجلد الخاص بالتطبيق على <a data-ss1613553322="1" href="https://github.com/fullstack-hy2020/part2-notes/tree/part5-10" rel="external nofollow">GitHub</a>
</p>

<h2>
	تغيير أهمية ملاحظة
</h2>

<p>
	لنلقي نظرة أخيرًا على الاختبار الذي أجريناه لتغيير أهمية الملاحظة. سنغير أولًا كتلة التنسيق لتنشئ ثلاث ملاحظات بدلًا من واحدة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_76" style="">
<span class="pln">describe</span><span class="pun">(</span><span class="str">'when logged in'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  describe</span><span class="pun">(</span><span class="str">'and several notes exist'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    beforeEach</span><span class="pun">(</span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      cy</span><span class="pun">.</span><span class="pln">createNote</span><span class="pun">({</span><span class="pln"> content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'first note'</span><span class="pun">,</span><span class="pln"> important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">})</span><span class="pln">      
        cy</span><span class="pun">.</span><span class="pln">createNote</span><span class="pun">({</span><span class="pln"> content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'second note'</span><span class="pun">,</span><span class="pln"> important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">})</span><span class="pln">     
        cy</span><span class="pun">.</span><span class="pln">createNote</span><span class="pun">({</span><span class="pln"> content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'third note'</span><span class="pun">,</span><span class="pln"> important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">})</span><span class="pln">    
    </span><span class="pun">})</span><span class="pln">

    it</span><span class="pun">(</span><span class="str">'one of those can be made important'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'second note'</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'make important'</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">click</span><span class="pun">()</span><span class="pln">

      cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'second note'</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'make not important'</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	كيف يعمل الأمر <a data-ss1613553322="1" href="https://docs.cypress.io/api/commands/contains.html" rel="external nofollow">cy.contains</a> في الواقع؟
</p>

<p>
	سننقر الأمر <code>(cy.contains('second note'</code> في <a data-ss1613553322="1" href="https://docs.cypress.io/guides/core-concepts/test-runner.htm" rel="external nofollow">مُنفّذ الاختبار</a> (TestRunner) الخاص بالمكتبة Cypress. سنجد أن هذا الأمر سيبحث عن عنصر يحوي على النص "second note".
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="57871" data-unique="75yflzqt1" src="https://academy.hsoub.com/uploads/monthly_2021_02/test_runer_06.png.d7971f1145efcf4fa9c36546a9efa9a5.png" alt="test_runer_06.png"></p>

<p>
	بالنقر على السطر الثاني <code>('contains('make important.</code> :
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="57868" data-unique="2ztv69bwb" src="https://academy.hsoub.com/uploads/monthly_2021_02/est_runner_make_important_07.png.3ab59da1cfcc064f9831ea1c9b4a4fb1.png" alt="est_runner_make_important_07.png"></p>

<p>
	سنجد الزر "make important" المرتبط بالملاحظة الثانية:
</p>

<p>
	يستأنف الأمر <code>contains</code> الثاني عندما يُقيّد في السلسة، البحث في المكوِّن الذي وجده الأمر الأول.
</p>

<p>
	فإن لم نقيّد الأمر وكتبنا بدلًا عن ذلك:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_78" style="">
<span class="pln">cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'second note'</span><span class="pun">)</span><span class="pln">
cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'make important'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span></pre>

<p>
	ستكون النتيجة مختلفة تمامًا. حيث سينقر السطر الثاني الزر المتعلق بالملاحظة الخاطئة:
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="57872" data-unique="1r2zuvphw" src="https://academy.hsoub.com/uploads/monthly_2021_02/test_wrong_note_08.png.c5f9911cc55a8f2f34eafc081a6ad680.png" alt="test_wrong_note_08.png"></p>

<p>
	عندما تنفذ الشيفرة الاختبارات، عليك التحقق من خلال مُنفِّذ الاختبارات أن الاختبار يجري على المكوِّن الصحيح.
</p>

<p>
	لنعدّل المكوِّن <code>Note</code> بحيث يُصيّر نص الملاحظة كنعصر <code>span</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_80" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Note</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> note</span><span class="pun">,</span><span class="pln"> toggleImportance </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> label </span><span class="pun">=</span><span class="pln"> note</span><span class="pun">.</span><span class="pln">important
    </span><span class="pun">?</span><span class="pln"> </span><span class="str">'make not important'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">'make important'</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">li className</span><span class="pun">=</span><span class="str">'note'</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">span</span><span class="pun">&gt;{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">content</span><span class="pun">}&lt;/</span><span class="pln">span</span><span class="pun">&gt;</span><span class="pln">      
      </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">toggleImportance</span><span class="pun">}&gt;{</span><span class="pln">label</span><span class="pun">}&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيفشل الاختبار!
</p>

<p>
	وكما يبين لنا مُنفِّذ الاختبار، سيعيد الأمر <code>('cy.contains('second note</code> المكوّن الذي يحمل النص الصحيح لكن الزر ليس موجودًا ضمنه.
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="57870" data-unique="8zxzjuad1" src="https://academy.hsoub.com/uploads/monthly_2021_02/test_no_content_09.png.a595bc1533800af88a7c3656bcdf00de.png" alt="test_no_content_09.png"></p>

<p>
	إحدى طرق إصلاح الأمر هي التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_82" style="">
<span class="pln">it</span><span class="pun">(</span><span class="str">'other of those can be made important'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'second note'</span><span class="pun">).</span><span class="pln">parent</span><span class="pun">().</span><span class="pln">find</span><span class="pun">(</span><span class="str">'button'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span><span class="pln">
  cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'second note'</span><span class="pun">).</span><span class="pln">parent</span><span class="pun">().</span><span class="pln">find</span><span class="pun">(</span><span class="str">'button'</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">.</span><span class="pln">should</span><span class="pun">(</span><span class="str">'contain'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'make not important'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	نستخدم في السطر الأول الأمر <a data-ss1613553322="1" href="https://docs.cypress.io/api/commands/parent.html" rel="external nofollow">parent</a> للوصول إلى العنصر الأب للعنصر الذي يحتوي على الملاحظة الثانية وسيجد الزر داخله. ننقر بعدها على الزر ونتحقق من تغيّر النص الظاهر عليه.
</p>

<p>
	لاحظ أننا نستخدم الأمر <a data-ss1613553322="1" href="https://docs.cypress.io/api/commands/find.html#Syntax" rel="external nofollow">find</a> للبحث عن الزر. إذ لا يمكننا استخدام الأمر <a data-ss1613553322="1" href="https://docs.cypress.io/api/commands/get.html" rel="external nofollow">cy.get</a> لأنه يبحث دائمًا عن المطلوب في الصفحة بأكملها، وسيعيد الأزرار الخمسة الموجودة.
</p>

<p>
	لسوء الحظ علينا القيام ببعض عمليات النسخ واللصق في اختبارنا، لأن شيفرة البحث عن الزر الصحيح هي نفسها.
</p>

<p>
	في هذه الحالات، يمكن استخدام الأمر <a data-ss1613553322="1" href="https://docs.cypress.io/api/commands/as.html" rel="external nofollow">as</a>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_84" style="">
<span class="pln">it</span><span class="pun">.</span><span class="pln">only</span><span class="pun">(</span><span class="str">'other of those can be made important'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'second note'</span><span class="pun">).</span><span class="pln">parent</span><span class="pun">().</span><span class="pln">find</span><span class="pun">(</span><span class="str">'button'</span><span class="pun">).</span><span class="pln">as</span><span class="pun">(</span><span class="str">'theButton'</span><span class="pun">)</span><span class="pln">
  cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'@theButton'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span><span class="pln">
  cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'@theButton'</span><span class="pun">).</span><span class="pln">should</span><span class="pun">(</span><span class="str">'contain'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'make not important'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	سيجد السطر الأول الآن الزر الصحيح، ثم يستخدم <code>as</code> لتخزينه بالاسم <code>theButton</code>. ستتمكن السطور التالية من استخدام العنصر السابق بالشكل <code>('cy.get('@theButton</code>.
</p>

<h2>
	تنفيذ وتنقيح الاختبارات
</h2>

<p>
	سنذكر أخيرًا بعض الملاحظات عن عمل Cypress وعن تنقيح الاختبارات.
</p>

<p>
	يعطي شكل اختبارت Cypress انطباعًا أن الاختبارات هي شيفرة JavaScript وأنه بالإمكان تنفيذ التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_86" style="">
<span class="kwd">const</span><span class="pln"> button </span><span class="pun">=</span><span class="pln"> cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'login'</span><span class="pun">)</span><span class="pln">
button</span><span class="pun">.</span><span class="pln">click</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">debugger</span><span class="pun">()</span><span class="pln"> 
cy</span><span class="pun">.</span><span class="pln">contains</span><span class="pun">(</span><span class="str">'logout'</span><span class="pun">).</span><span class="pln">click</span><span class="pun">()</span></pre>

<p>
	لن تعمل الشيفرة السابقة. فعندما تنفذ Cypress اختبارًا فستضيف كل أمر <code>cy</code> إلى صف انتظار لتنفيذه. وعندما تُنفَّذ شيفرة الاختبار، ستُنفّذ الأوامر في الصف واحدًا بعد الآخر.
</p>

<p>
	تعيد Cypress دائمًا كائنًا غير محدد، لذلك سيسبب استخدام الأمر<code>()button.click</code> خطأً. ولن يُوقف تشغيل المنقح تنفيذ الشيفرة في الفترة ما بين أمرين، لكن قبل تنفيذ الأوامر كلها.
</p>

<p>
	تشابه أوامر Cypress الوعود. فإن أردنا الوصول إلى القيم التي تعيدها، علينا استخدام التابع <code>then</code>. فعلى سبيل المثال، ستطبع الشيفرة التالية عدد الأزرار في التطبيق، وستنقر الزر الأول:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_88" style="">
<span class="pln">it</span><span class="pun">(</span><span class="str">'then example'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  cy</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'button'</span><span class="pun">).</span><span class="pln">then</span><span class="pun">(</span><span class="pln"> buttons </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'number of buttons'</span><span class="pun">,</span><span class="pln"> buttons</span><span class="pun">.</span><span class="pln">length</span><span class="pun">)</span><span class="pln">
    cy</span><span class="pun">.</span><span class="pln">wrap</span><span class="pun">(</span><span class="pln">buttons</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]).</span><span class="pln">click</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	<a data-ss1613553322="1" href="https://docs.cypress.io/api/commands/debug.html" rel="external nofollow">من الممكن</a> إيقاف تنفيذ الشيفرة باستخدام المنقح. إذ يعمل المنقح فقط، إن كانت طرفية تطوير مُنفّذ الاختبارات في Cypress مفتوحةً.
</p>

<p>
	تقدم لك طرفية التطوير كل الفائدة عند تنقيح الاختبارات. فيمكن أن تتابع طلبات HTTP التي ترسلها الاختبارات ضمن النافذة <code>Network</code>، كما ستظهر لك الطرفية الكثير من المعلومات حول الاختبارات:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-ss1613553322="1" href="https://academy.hsoub.com/uploads/monthly_2021_02/console_info_10.png.1fca01ae26c7c97408407aac937d1810.png" data-fileid="57863" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="57863" data-unique="yj5ufouc5" src="https://academy.hsoub.com/uploads/monthly_2021_02/console_info_10.png.1fca01ae26c7c97408407aac937d1810.png" alt="console_info_10.png"></a>
</p>

<p>
	نفّذنا حتى اللحظة جميع اختبارات Cypress باستخدام الواجهة الرسومية لمُنفِّذ الاختبار. من الممكن أيضًا <a data-ss1613553322="1" href="https://docs.cypress.io/guides/guides/command-line.html" rel="external nofollow">تشغيلها من سطر الأوامر</a>. وكل ما علينا هو إضافة سكربت npm التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_90" style="">
<span class="pln">  </span><span class="str">"scripts"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"start"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"react-scripts start"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"build"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"react-scripts build"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"test"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"react-scripts test"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"eject"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"react-scripts eject"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"server"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"json-server -p3001 --watch db.json"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"cypress:open"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"cypress open"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"test:e2e"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"cypress run"</span><span class="pln">  </span><span class="pun">},</span></pre>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-ss1613553322="1" href="https://academy.hsoub.com/uploads/monthly_2021_02/e2e_test_command_line_11.png.50a91d716bfb35f0db974cd62e3fb97a.png" data-fileid="57867" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="57867" data-unique="sdtmz3s6l" src="https://academy.hsoub.com/uploads/monthly_2021_02/e2e_test_command_line_11.thumb.png.634f4423bf11560b2b0632ccbca25a5c.png" alt="e2e_test_command_line_11.png"></a>
</p>

<p>
	وهكذا سنتمكن من تنفيذ الاختبارات باستخدام سطر الأوامر بتنفيذ الأمر <code>npm test:e2e</code>
</p>

<p>
	انتبه إلى أن الفيديو الذي يوثق عملية التنفيذ سيُخزّن ضمن المجلد cypress/vedios، لذا من المحتمل أن تجعل git يتجاهل هذا الملف.
</p>

<p>
	ستجد شيفرة الواجهة الأمامية والاختبارت ضمن الفرع part5-11 في المجلد المخصص للتطبيق على <a data-ss1613553322="1" href="https://github.com/fullstack-hy2020/part2-notes/tree/part5-11" rel="external nofollow">GitHub</a>
</p>

<h2>
	التمارين 5.17 - 5.22
</h2>

<p>
	سننفذ بعض اختبارات E2E في التمارين الأخيرة من هذا القسم على تطبيق المدونة. تكفي مادة هذا القسم لتنفيذ التمارين. وينبغي عليك بالتأكيد أن تتحق من توثيق المكتبة Cypress.
</p>

<p>
	ننصح بقراءة المقالة <a data-ss1613553322="1" href="https://docs.cypress.io/guides/core-concepts/introduction-to-cypress.html#Cypress-Can-Be-Simple-Sometimes" rel="external nofollow">Introduction to Cypress</a> والتي تذكر مقدمتها ما يلي:
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p>
		هذا هو الدليل الوحيد والأكثر أهمية عن كيفية تنفيذ الاختبارات باستخدام Cypress. إقرأه وأفهمه.
	</p>
</blockquote>

<h3>
	5.17 اختبارت مشتركة للواجهتين لتطبيق المدونة: خطوة 1
</h3>

<p>
	هيئ Cypress لتعمل على تطبيقك. ثم نفذ اختبارًا يتحقق أن التطبيق سيظهر واجهة تسجيل الدخول بشكل افتراضي.
</p>

<p>
	على شيفرة الاختبار أن تكون كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_93" style="">
<span class="pln">describe</span><span class="pun">(</span><span class="str">'Blog app'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  beforeEach</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    cy</span><span class="pun">.</span><span class="pln">request</span><span class="pun">(</span><span class="str">'POST'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'http://localhost:3001/api/testing/reset'</span><span class="pun">)</span><span class="pln">
    cy</span><span class="pun">.</span><span class="pln">visit</span><span class="pun">(</span><span class="str">'http://localhost:3000'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">

  it</span><span class="pun">(</span><span class="str">'Login form is shown'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ...</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	يجب أن تُفرّغ كتلة التنسيق <code>beforeEach</code> قاعدة البيانات كما فعلنا في هذا الفصل سابقًا.
</p>

<h3>
	5.18 اختبارت مشتركة للواجهتين لتطبيق المدونة: خطوة 2
</h3>

<p>
	أجر اختبارات على تسجيل الدخول. اختبر حالتي التسجيل الناجحة و المخفقة. أنشئ مستخدمًا جديدًا للاختبار عن طريق الكتلة <code>beforeEach</code>.
</p>

<p>
	سيتوسع شكل التطبيق ليصبح على النحو:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_95" style="">
<span class="pln">describe</span><span class="pun">(</span><span class="str">'Blog app'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  beforeEach</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    cy</span><span class="pun">.</span><span class="pln">request</span><span class="pun">(</span><span class="str">'POST'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'http://localhost:3001/api/testing/reset'</span><span class="pun">)</span><span class="pln">
    </span><span class="com">// create here a user to backend</span><span class="pln">
    cy</span><span class="pun">.</span><span class="pln">visit</span><span class="pun">(</span><span class="str">'http://localhost:3000'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">

  it</span><span class="pun">(</span><span class="str">'Login form is shown'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ...</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">

  describe</span><span class="pun">(</span><span class="str">'Login'</span><span class="pun">,</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    it</span><span class="pun">(</span><span class="str">'succeeds with correct credentials'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="com">// ...</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">

    it</span><span class="pun">(</span><span class="str">'fails with wrong credentials'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="com">// ...</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	<strong>تمرين اختياري لعلامة أعلى</strong>: تحقق أن التنبيه سيُعرض باللون الأحمر عند إخفاق تسجيل الدخول
</p>

<h3>
	5.19 اختبارت مشتركة للواجهتين لتطبيق المدونة: خطوة 3
</h3>

<p>
	نفذ اختبارًا يتحقق أن المستخدم الذي يسجل دخوله سيتمكن من إنشاء مدونة جديدة.
</p>

<p>
	قد تكون بنية شيفرة الاختبار الآن كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5255_97" style="">
<span class="pln">describe</span><span class="pun">(</span><span class="str">'Blog app'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">

  describe</span><span class="pun">.</span><span class="pln">only</span><span class="pun">(</span><span class="str">'When logged in'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    beforeEach</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="com">// log in user here</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">

    it</span><span class="pun">(</span><span class="str">'A blog can be created'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="com">// ...</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">

</span><span class="pun">})</span></pre>

<p>
	ويجب أن يتأكد الاختبار أن المدونة الجديدة ستضاف إلى قائمة جميع المدونات.
</p>

<h3>
	5.20 اختبارت مشتركة للواجهتين لتطبيق المدونة: خطوة 4
</h3>

<p>
	نفذ اختبارًا يتحقق من إمكانية إعجاب مستخدم بمدونة.
</p>

<h3>
	5.21 اختبارت مشتركة للواجهتين لتطبيق المدونة: خطوة 5
</h3>

<p>
	نفذ اختبارًا يتحقق من إمكانية حذف المستخدم لمدونة قد أنشأها سابقًا.
</p>

<p>
	<strong>تمرين اختياري لعلامة أعلى</strong>: تحقق أن المستخدمين الآخرين لن يكونوا قادرين على حذفها.
</p>

<h3>
	5.22 اختبارت مشتركة للواجهتين لتطبيق المدونة: خطوة 6
</h3>

<p>
	نفذ اختبارًا يتحقق أن قائمة المدونات مرتبة حسب تسلسل الإعجابات، من الأكثر إلى الأقل.
</p>

<p>
	قد يحمل هذا التمرين بعض الصعوبة. أحد الحلول المقترحة هو إيجاد جميع المدونات، ثم الموازنة بينها باستخدام التابع <a data-ss1613553322="1" href="https://docs.cypress.io/api/commands/then.html#DOM-element" rel="external nofollow">then</a>.
</p>

<p>
	هكذا نكون قد وصلنا إلى التمرين الأخير في القسم، وحان الوقت لتسليم الحلول إلى GitHub، والإشارة إلى أنك سلمت التمارين المنتهية ضمن <a data-ss1613553322="1" href="https://studies.cs.helsinki.fi/stats/courses/fullstackopen" rel="external nofollow">منظومة تسليم التمارين</a>.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a data-ss1613553322="1" href="https://fullstackopen.com/en/part5/end_to_end_testing" rel="external nofollow">end to end testing</a> من سلسلة <a data-ss1613553322="1" href="https://fullstackopen.com/en/" rel="external nofollow">Deep Dive Into Modern Web Development</a>
</p>
]]></description><guid isPermaLink="false">1139</guid><pubDate>Wed, 17 Feb 2021 09:34:48 +0000</pubDate></item><item><title>&#x627;&#x62E;&#x62A;&#x628;&#x627;&#x631; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; React &#x628;&#x627;&#x633;&#x62A;&#x639;&#x645;&#x627;&#x644; Jest &#x648;&#x645;&#x643;&#x62A;&#x628;&#x629; React Testing Library</title><link>https://academy.hsoub.com/programming/javascript/react/%D8%A7%D8%AE%D8%AA%D8%A8%D8%A7%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-react-%D8%A8%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-jest-%D9%88%D9%85%D9%83%D8%AA%D8%A8%D8%A9-react-testing-library-r1138/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_02/602cd90f2893f_--React.png.f3d191a3f499912f1be18e097da304aa.png" /></p>

<p>
	توجد طرق عدة لاختبار تطبيقات React. سنلقي نظرة عليها في المادة القادمة.
</p>

<p>
	نضيف الاختبارات عبر مكتبة الاختبارت <a data-ss1613551880="1" href="http://jestjs.io/" rel="external nofollow">Jest</a> التي طورتها Facebook والتي استخدمناها في القسم السابق. تُهيئ Jest افتراضيًا في التطبيقات التي تبنى باستخدام create-react-apps.
</p>

<p>
	بالإضافة إلى Jest، سنحتاج إلى مكتبة اختبارت أخرى تساعدنا في تصيير المكوِّنات لأغراض الاختبارات. إن أفضل خيار متاح أمامنا حاليًا هي مكتبة اختبارات React تدعى <a data-ss1613551880="1" href="https://github.com/testing-library/react-testing-library" rel="external nofollow">react-testing-library</a> والتي زادت شعبيتها كثيرًا في الآونة الأخيرة.
</p>

<p>
	إذًا سنثبت هذه المكتبة بتنفيذ الأمر التالي:
</p>

<pre class="ipsCode">
npm install --save-dev @testing-library/react @testing-library/jest-dom
</pre>

<p>
	سنكتب أولًا اختبارات للمكوِّن المسؤول عن تصيير الملاحظة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5254_9" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Note</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> note</span><span class="pun">,</span><span class="pln"> toggleImportance </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> label </span><span class="pun">=</span><span class="pln"> note</span><span class="pun">.</span><span class="pln">important
    </span><span class="pun">?</span><span class="pln"> </span><span class="str">'make not important'</span><span class="pln">
    </span><span class="pun">:</span><span class="pln"> </span><span class="str">'make important'</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">li className</span><span class="pun">=</span><span class="str">'note'</span><span class="pun">&gt;</span><span class="pln">      
      </span><span class="pun">{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">content</span><span class="pun">}</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">toggleImportance</span><span class="pun">}&gt;{</span><span class="pln">label</span><span class="pun">}&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لاحظ أن للعنصر <code>li</code> صنف تنسيق <a data-ss1613551880="1" href="https://wiki.hsoub.com/React/dom_elements#className" rel="external">CSS</a> اسمه <code>note</code>، يستخدم للوصول إلى المكوِّن في اختباراتنا.
</p>

<h2>
	تصيير المكوّن للاختبارات
</h2>

<p>
	سنكتب اختبارنا في الملف Note.test.js الموجود في نفس مجلد المكوَّن. يتحقق الاختبار الأول من أن المكوّن سيصيّر محتوى الملاحظة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5254_12" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="str">'@testing-library/jest-dom/extend-expect'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> render </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'@testing-library/react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Note</span><span class="pln"> from </span><span class="str">'./Note'</span><span class="pln">

test</span><span class="pun">(</span><span class="str">'renders content'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> note </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Component testing is done with react-testing-library'</span><span class="pun">,</span><span class="pln">
    important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> component </span><span class="pun">=</span><span class="pln"> render</span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">Note</span><span class="pln"> note</span><span class="pun">={</span><span class="pln">note</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">

  expect</span><span class="pun">(</span><span class="pln">component</span><span class="pun">.</span><span class="pln">container</span><span class="pun">).</span><span class="pln">toHaveTextContent</span><span class="pun">(</span><span class="pln">
    </span><span class="str">'Component testing is done with react-testing-library'</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	يصيّر الاختبار المكوِّن بعد التهيئة الأولية باستخدام التابع <a data-ss1613551880="1" href="https://testing-library.com/docs/react-testing-library/api#render" rel="external nofollow">render</a> العائد للمكتبة react-testing-library:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5254_15" style="">
<span class="kwd">const</span><span class="pln"> component </span><span class="pun">=</span><span class="pln"> render</span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="typ">Note</span><span class="pln"> note</span><span class="pun">={</span><span class="pln">note</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
</span><span class="pun">)</span></pre>

<p>
	تُصيّر مكوِّنات React عادة إلى DOM (نموذج كائن document). لكن التابع <code>render</code> سيصيرها إلى تنسيق مناسب للاختبارات دون أن يصيّرها إلى DOM.
</p>

<p>
	يعيد التابع <code>render</code> كائنًا له عدة <a data-ss1613551880="1" href="https://testing-library.com/docs/react-testing-library/api#render-result" rel="external nofollow">خصائص</a>، تدعى إحداها <code>container</code> وتحتوي كل شيفرة HTML التي يصيّرها المكوِّن.
</p>

<p>
	تتأكد التعليمة <code>expect</code> أن المكوِّن سيصيّر النص الصحيح، وهو في حالتنا محتوى الملاحظة.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5254_17" style="">
<span class="pln">expect</span><span class="pun">(</span><span class="pln">component</span><span class="pun">.</span><span class="pln">container</span><span class="pun">).</span><span class="pln">toHaveTextContent</span><span class="pun">(</span><span class="pln">
  </span><span class="str">'Component testing is done with react-testing-library'</span><span class="pln">
</span><span class="pun">)</span></pre>

<h2>
	تنفيذ الاختبارات
</h2>

<p>
	تهيئ Create-react-app الاختبارت بحيث تُنفَّذ في وضع المراقبة افتراضيُا. ويعني ذلك أن الأمر <code>npm test</code> لن يتوقف بعد أن ينتهي تنفيذ الاختبار، بل ينتظر بدلًا من ذلك أية تغييرات تجري على الشيفرة. وبمجرد حفظ التغييرات الجديدة، سيُنفَّذ الاختبار تلقائيًا من جديد وهكذا.
</p>

<p>
	إن أردت تنفيذ الاختبار بالوضع الاعتيادي، نفذ الأمر:
</p>

<pre class="ipsCode">
CI=true npm test
</pre>

<p>
	<strong>ملاحظة</strong>: من الممكن أن ترى تحذيرًا على الطرفية إن لم تكن قد ثبتت Watchman. وهو تطبيق طورته Facebook ليراقب التغيرات التي تحدث في الملفات. سيسرع التطبيق من تنفيذ الاختبارات وسيساعد في التخلص من التحذيرات التي تظهر على الشاشة في وضع المراقبة ابتداء من الإصدار Sierra على الأقل لنظام التشغيل macOS.
</p>

<p>
	يمكنك أن تجد تعليمات استخدام تطبيق Watchman في أنظمة التشغيل المختلفة على <a data-ss1613551880="1" href="https://facebook.github.io/watchman" rel="external nofollow">الموقع الرسمي للتطبيق</a>.
</p>

<h2>
	موقع ملف الاختبار
</h2>

<p>
	تتبع React <a data-ss1613551880="1" href="https://medium.com/@JeffLombardJr/organizing-tests-in-jest-17fc431ff850" rel="external nofollow">تقليدين مختلفين</a> (على الأقل) لاختيار مكان ملف الاختبار. وقد اتبعنا التقليد الحالي الذي ينص أن يكون ملف الاختبار في نفس مجلد المكوِّن الذي يُختبر.
</p>

<p>
	أما التقليد الأخر فينص على وضع ملفات الاختبار في مجلد خاص بها. وأيًا يكن اختيارنا ستجد حتمًا من يعارض ذلك.
</p>

<p>
	وقد اخترنا وضع الملف في نفس مجلد المكوِّن لأن create<em>react</em>app قد هيأت التطبيق لذلك افتراضيًا.
</p>

<h2>
	البحث عن محتوى محدد ضمن المكوِّن
</h2>

<p>
	تقدم الحزمة react-testing-library طرقًا كثيرةً للبحث في محتويات المكوِّنات التي نختبرها.
</p>

<p>
	لنوسع تطبيقنا قليلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5254_19" style="">
<span class="pln">test</span><span class="pun">(</span><span class="str">'renders content'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> note </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Component testing is done with react-testing-library'</span><span class="pun">,</span><span class="pln">
    important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> component </span><span class="pun">=</span><span class="pln"> render</span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">Note</span><span class="pln"> note</span><span class="pun">={</span><span class="pln">note</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">

  </span><span class="com">// method 1</span><span class="pln">
  expect</span><span class="pun">(</span><span class="pln">component</span><span class="pun">.</span><span class="pln">container</span><span class="pun">).</span><span class="pln">toHaveTextContent</span><span class="pun">(</span><span class="pln">
    </span><span class="str">'Component testing is done with react-testing-library'</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">

  </span><span class="com">// method 2</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> element </span><span class="pun">=</span><span class="pln"> component</span><span class="pun">.</span><span class="pln">getByText</span><span class="pun">(</span><span class="pln">
    </span><span class="str">'Component testing is done with react-testing-library'</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
  expect</span><span class="pun">(</span><span class="pln">element</span><span class="pun">).</span><span class="pln">toBeDefined</span><span class="pun">()</span><span class="pln">

  </span><span class="com">// method 3</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> div </span><span class="pun">=</span><span class="pln"> component</span><span class="pun">.</span><span class="pln">container</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'.note'</span><span class="pun">)</span><span class="pln">
  expect</span><span class="pun">(</span><span class="pln">div</span><span class="pun">).</span><span class="pln">toHaveTextContent</span><span class="pun">(</span><span class="pln">
    </span><span class="str">'Component testing is done with react-testing-library'</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	تستخدم الطريق الأولى التابع <code>toHaveTextContent</code> للبحث عن نص مطابق لكامل شيفرة HTML التي يصيّرها المكوِّن. وهذا التابع هو واحد من عدة توابع مُطابَقة تقدمها المكتبة <a data-ss1613551880="1" href="https://github.com/testing-library/jest-dom#tohavetextcontent" rel="external nofollow">jest-dom</a>.
</p>

<p>
	بينما تستخدم الطريقة الثانية التابع <a data-ss1613551880="1" href="https://testing-library.com/docs/dom-testing-library/api-queries#bytext" rel="external nofollow">getByText</a> العائد للكائن الذي يعيده التابع <code>render</code>. حيث يعيد التابع <code>getByText</code> العنصر الذي يحتوي النص الذي نبحث عنه. وسيقع استثناء إن لم يجد عنصرًا مطابقًا. لهذا لسنا بحاجة عمليًا لتخصيص أية استثناءات إضافية.
</p>

<p>
	تقتضي الطريقة الثالثة البحث عن عنصر محدد من عناصر HTML التي يصيّرها المكوِّن باستخدام التابع <a data-ss1613551880="1" href="https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector" rel="external nofollow">querySelector</a> الذي يستقبل كوسيط <a data-ss1613551880="1" href="https://wiki.hsoub.com/CSS#.D8.A7.D9.84.D9.85.D9.8F.D8.AD.D8.AF.D9.90.D9.91.D8.AF.D8.A7.D8.AA" rel="external">مُحدِّد CSS</a>.
</p>

<p>
	تستخدم الطريقتين الأخيريتين التابعين <code>getByText</code> و<code>querySelector</code> لإيجاد العنصر الذي يحقق بعض الشروط في المكوّن المصيَّر. وهناك الكثير من التوابع <a data-ss1613551880="1" href="https://testing-library.com/docs/dom-testing-library/api-queries" rel="external nofollow">المتاحة للبحث</a> أيضًا.
</p>

<h2>
	تنقيح الاختبارات
</h2>

<p>
	ستواجهنا تقليديًا العديد من المشاكل عند كتابة وتنفيذ الاختبارات. يمتلك الكائن الذي يعيده التابع <code>render</code> التابع <a data-ss1613551880="1" href="https://testing-library.com/docs/react-testing-library/api#debug" rel="external nofollow">debug</a> الذي يمكن استخدامه لطباعة شيفرة HTML التي يصيّرها المكوَّن على الطرفية. لنجرب ذلك بإجراء بعض التعديلات على الشيفرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5254_24" style="">
<span class="pln">test</span><span class="pun">(</span><span class="str">'renders content'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> note </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Component testing is done with react-testing-library'</span><span class="pun">,</span><span class="pln">
    important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> component </span><span class="pun">=</span><span class="pln"> render</span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">Note</span><span class="pln"> note</span><span class="pun">={</span><span class="pln">note</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">

  component</span><span class="pun">.</span><span class="pln">debug</span><span class="pun">()</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	يمكنك أن ترى شيفرة HTML التي يولدها المكوِّن على الطرفية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5254_26" style="">
<span class="pln">console.log node_modules/@testing-library/react/dist/index.js:90
  </span><span class="tag">&lt;body&gt;</span><span class="pln">
    </span><span class="tag">&lt;div&gt;</span><span class="pln">
      </span><span class="tag">&lt;li</span><span class="pln">
        </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"note"</span><span class="pln">
      </span><span class="tag">&gt;</span><span class="pln">
        Component testing is done with react-testing-library
        </span><span class="tag">&lt;button&gt;</span><span class="pln">
          make not important
        </span><span class="tag">&lt;/button&gt;</span><span class="pln">
      </span><span class="tag">&lt;/li&gt;</span><span class="pln">
    </span><span class="tag">&lt;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;/body&gt;</span></pre>

<p>
	يمكنك أيضًا البحث عن جزء صغير من المكوّن وطباعة شيفرة HTML التي يحتويها. نستخدم لهذا الغرض التابع <code>prettyDOM</code> الذي يمكن إدراجه من الحزمة testing-library/dom@ التي تُثبـت تلقائيًا مع المكتبة react-testing-library.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5254_28" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="str">'@testing-library/jest-dom/extend-expect'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> render </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'@testing-library/react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> prettyDOM </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'@testing-library/dom'</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Note</span><span class="pln"> from </span><span class="str">'./Note'</span><span class="pln">

test</span><span class="pun">(</span><span class="str">'renders content'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> note </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Component testing is done with react-testing-library'</span><span class="pun">,</span><span class="pln">
    important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> component </span><span class="pun">=</span><span class="pln"> render</span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">Note</span><span class="pln"> note</span><span class="pun">={</span><span class="pln">note</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> li </span><span class="pun">=</span><span class="pln"> component</span><span class="pun">.</span><span class="pln">container</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'li'</span><span class="pun">)</span><span class="pln">

  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">prettyDOM</span><span class="pun">(</span><span class="pln">li</span><span class="pun">))})</span></pre>

<p>
	استخدمنا هنا مُحدِّد CSS للعثور على العنصر <code>li</code> داخل المكوِّن، ومن ثم طباعة محتواه:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5254_30" style="">
<span class="pln">console.log src/components/Note.test.js:21
  </span><span class="tag">&lt;li</span><span class="pln">
    </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"note"</span><span class="pln">
  </span><span class="tag">&gt;</span><span class="pln">
    Component testing is done with react-testing-library
    </span><span class="tag">&lt;button&gt;</span><span class="pln">
      make not important
    </span><span class="tag">&lt;/button&gt;</span><span class="pln">
  </span><span class="tag">&lt;/li&gt;</span></pre>

<h2>
	النقر على الأزرار أثناء الاختبارات
</h2>

<p>
	يتحقق المكون <code>Note</code>، بالإضافة إلى عرضه محتوى الملاحظة، أن النقر على الزر المجاور للملاحظة سيستدعي دالة معالج الحدث <code>toggleImportance</code>.
</p>

<p>
	وللتحقق من هذه الوظيفة يمكن تنفيذ الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5254_32" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> render</span><span class="pun">,</span><span class="pln"> fireEvent </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'@testing-library/react'</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> prettyDOM </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'@testing-library/dom'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Note</span><span class="pln"> from </span><span class="str">'./Note'</span><span class="pln">

</span><span class="com">// ...</span><span class="pln">

test</span><span class="pun">(</span><span class="str">'clicking the button calls event handler once'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> note </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Component testing is done with react-testing-library'</span><span class="pun">,</span><span class="pln">
    important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> mockHandler </span><span class="pun">=</span><span class="pln"> jest</span><span class="pun">.</span><span class="pln">fn</span><span class="pun">()</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> component </span><span class="pun">=</span><span class="pln"> render</span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">Note</span><span class="pln"> note</span><span class="pun">={</span><span class="pln">note</span><span class="pun">}</span><span class="pln"> toggleImportance</span><span class="pun">={</span><span class="pln">mockHandler</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> button </span><span class="pun">=</span><span class="pln"> component</span><span class="pun">.</span><span class="pln">getByText</span><span class="pun">(</span><span class="str">'make not important'</span><span class="pun">)</span><span class="pln">
  fireEvent</span><span class="pun">.</span><span class="pln">click</span><span class="pun">(</span><span class="pln">button</span><span class="pun">)</span><span class="pln">

  expect</span><span class="pun">(</span><span class="pln">mockHandler</span><span class="pun">.</span><span class="pln">mock</span><span class="pun">.</span><span class="pln">calls</span><span class="pun">).</span><span class="pln">toHaveLength</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	سنجد عدة نقاط هامة متعلقة بهذا الاختبار. فمعالج الحدث هو <a data-ss1613551880="1" href="https://facebook.github.io/jest/docs/en/mock-functions.html" rel="external nofollow">دالة محاكاة</a> تُعرَّف باستخدام Jest كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5254_34" style="">
<span class="kwd">const</span><span class="pln"> mockHandler </span><span class="pun">=</span><span class="pln"> jest</span><span class="pun">.</span><span class="pln">fn</span><span class="pun">()</span></pre>

<p>
	يعثر الاختبار على الزر عن طريق النص الذي يظهر عليه بعد تصيير المكون ومن ثم سينقره:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5254_36" style="">
<span class="kwd">const</span><span class="pln"> button </span><span class="pun">=</span><span class="pln"> getByText</span><span class="pun">(</span><span class="str">'make not important'</span><span class="pun">)</span><span class="pln">
fireEvent</span><span class="pun">.</span><span class="pln">click</span><span class="pun">(</span><span class="pln">button</span><span class="pun">)</span></pre>

<p>
	أما آلية النقر فينفذها التابع <a data-ss1613551880="1" href="https://testing-library.com/docs/api-events#fireevent" rel="external nofollow">fireEvent</a>.
</p>

<p>
	تتحقق التعليمة <code>expect</code> في هذا الاختبار من استدعاء دالة المحاكاة مرة واحدة فقط.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5254_40" style="">
<span class="pln">expect</span><span class="pun">(</span><span class="pln">mockHandler</span><span class="pun">.</span><span class="pln">mock</span><span class="pun">.</span><span class="pln">calls</span><span class="pun">).</span><span class="pln">toHaveLength</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span></pre>

<p>
	تستخدم أغراض ودوال المحاكاة كمكوِّنات لأغراض الاختبار وذلك لاستبدال اعتماديات المكوِّنات المختبرة. وتتميز المكوِّنات المحاكية بقدرتها على إعادة استجابة محضّرة مسبقًا، والتحقق من عدد المرات التي استدعيت بها الدالة المحاكية والمعاملات التي مُررت لها.
</p>

<p>
	و يعتبر استخدام الدالة المحاكية في مثالنا أمرًا نموذجيًا، لأنه يخبرنا بسهولة أن التابع قد استدعي مرة واحدة بالضبط.
</p>

<h2>
	اختبارات على المكوِّن Togglable
</h2>

<p>
	سنكتب عدة اختبارات للمكوِّن <code>togglable</code>. لنضف بداية صنف CSS الذي يدعى <code>togglableContent</code> إلى العنصر <code>div</code> الذي يعيد المكوّنات الأبناء:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5254_42" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Togglable</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">React</span><span class="pun">.</span><span class="pln">forwardRef</span><span class="pun">((</span><span class="pln">props</span><span class="pun">,</span><span class="pln"> ref</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div style</span><span class="pun">={</span><span class="pln">hideWhenVisible</span><span class="pun">}&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">toggleVisibility</span><span class="pun">}&gt;</span><span class="pln">
          </span><span class="pun">{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">buttonLabel</span><span class="pun">}</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div style</span><span class="pun">={</span><span class="pln">showWhenVisible</span><span class="pun">}</span><span class="pln"> className</span><span class="pun">=</span><span class="str">"togglableContent"</span><span class="pun">&gt;</span><span class="pln">        </span><span class="pun">{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">children</span><span class="pun">}</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">toggleVisibility</span><span class="pun">}&gt;</span><span class="pln">cancel</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	فيما يلي سنجد شيفرة الاختبارات التي سنجريها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5254_44" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="str">'@testing-library/jest-dom/extend-expect'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> render</span><span class="pun">,</span><span class="pln"> fireEvent </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'@testing-library/react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Togglable</span><span class="pln"> from </span><span class="str">'./Togglable'</span><span class="pln">

describe</span><span class="pun">(</span><span class="str">'&lt;Togglable /&gt;'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  let component

  beforeEach</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    component </span><span class="pun">=</span><span class="pln"> render</span><span class="pun">(</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Togglable</span><span class="pln"> buttonLabel</span><span class="pun">=</span><span class="str">"show..."</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">div className</span><span class="pun">=</span><span class="str">"testDiv"</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="typ">Togglable</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">)</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">

  test</span><span class="pun">(</span><span class="str">'renders its children'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    expect</span><span class="pun">(</span><span class="pln">
      component</span><span class="pun">.</span><span class="pln">container</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'.testDiv'</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">).</span><span class="pln">toBeDefined</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">

  test</span><span class="pun">(</span><span class="str">'at start the children are not displayed'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> div </span><span class="pun">=</span><span class="pln"> component</span><span class="pun">.</span><span class="pln">container</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'.togglableContent'</span><span class="pun">)</span><span class="pln">

    expect</span><span class="pun">(</span><span class="pln">div</span><span class="pun">).</span><span class="pln">toHaveStyle</span><span class="pun">(</span><span class="str">'display: none'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">

  test</span><span class="pun">(</span><span class="str">'after clicking the button, children are displayed'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> button </span><span class="pun">=</span><span class="pln"> component</span><span class="pun">.</span><span class="pln">getByText</span><span class="pun">(</span><span class="str">'show...'</span><span class="pun">)</span><span class="pln">
    fireEvent</span><span class="pun">.</span><span class="pln">click</span><span class="pun">(</span><span class="pln">button</span><span class="pun">)</span><span class="pln">

    </span><span class="kwd">const</span><span class="pln"> div </span><span class="pun">=</span><span class="pln"> component</span><span class="pun">.</span><span class="pln">container</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'.togglableContent'</span><span class="pun">)</span><span class="pln">
    expect</span><span class="pun">(</span><span class="pln">div</span><span class="pun">).</span><span class="pln">not</span><span class="pun">.</span><span class="pln">toHaveStyle</span><span class="pun">(</span><span class="str">'display: none'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">

</span><span class="pun">})</span></pre>

<p>
	تُستدعى الدالة <code>beforeEach</code> قبل كل اختبار، ومن ثم تصيّر المكوِّن <code>Togglable</code> إلى المتغير <code>component</code>.
</p>

<p>
	يتحقق الاختبار الأول أن المكوّن <code>Togglable</code> سيصيّر المكون الابن <code>&lt;div className="testDiv" /‎&gt;</code>. بينما تستخدم بقية الاختبارات التابع <a data-ss1613551880="1" href="https://www.npmjs.com/package/@testing-library/jest-dom#tohavestyle" rel="external nofollow">toHaveStyle</a> للتحقق أن المكوِّن الابن للمكوِّن <code>Togglable</code> ليس مرئيًا بشكل افتراضي، بالتحقق أن تنسيق العنصر <code>div</code> يتضمن الأمر <code>{ display: 'none' }</code>. اختبار آخر يتحقق من ظهور المكوّن عند النقر على الزر، أي بمعنًى آخر، لم يعد التنسيق الذي يسبب اختفاء المكوِّن مُسندًا إليه. وتذكر أن البحث عن الزر يجري اعتمادًا على النص الذي كُتب عليه، كما يمكن إيجاده اعتمادًا على مُحدِّد CSS.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5254_46" style="">
<span class="kwd">const</span><span class="pln"> button </span><span class="pun">=</span><span class="pln"> component</span><span class="pun">.</span><span class="pln">container</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'button'</span><span class="pun">)</span></pre>

<p>
	يحتوي المكوِّن على زرين، وطالما أن التابع <a data-ss1613551880="1" href="https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector" rel="external nofollow">querySelector</a> سيعيد الزر الأول الذي يتطابق مع معيار البحث، فسنكون قد حصلنا على الزر المطلوب مصادفةً.
</p>

<p>
	لنكتب اختبارًا يتحقق أن المحتوى المرئي يمكن أن يُخفى بالنقر على الزر الثاني للمكوِّن:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5254_48" style="">
<span class="pln">test</span><span class="pun">(</span><span class="str">'toggled content can be closed'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> button </span><span class="pun">=</span><span class="pln"> component</span><span class="pun">.</span><span class="pln">container</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'button'</span><span class="pun">)</span><span class="pln">
  fireEvent</span><span class="pun">.</span><span class="pln">click</span><span class="pun">(</span><span class="pln">button</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> closeButton </span><span class="pun">=</span><span class="pln"> component</span><span class="pun">.</span><span class="pln">container</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="pln">
    </span><span class="str">'button:nth-child(2)'</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
  fireEvent</span><span class="pun">.</span><span class="pln">click</span><span class="pun">(</span><span class="pln">closeButton</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> div </span><span class="pun">=</span><span class="pln"> component</span><span class="pun">.</span><span class="pln">container</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'.togglableContent'</span><span class="pun">)</span><span class="pln">
  expect</span><span class="pun">(</span><span class="pln">div</span><span class="pun">).</span><span class="pln">toHaveStyle</span><span class="pun">(</span><span class="str">'display: none'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	عرّفنا محدِّد تنسيق CSS لكي نستخدمه في إعادة الزر الثاني <code>(button:nth-child(2</code>. فليس من الحكمة الاعتماد على ترتيب الزر في المكوِّن، ومن الأجدى أن نجد الزر بناء على النص الذي يظهر عليه.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5254_50" style="">
<span class="pln">test</span><span class="pun">(</span><span class="str">'toggled content can be closed'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> button </span><span class="pun">=</span><span class="pln"> component</span><span class="pun">.</span><span class="pln">getByText</span><span class="pun">(</span><span class="str">'show...'</span><span class="pun">)</span><span class="pln">
  fireEvent</span><span class="pun">.</span><span class="pln">click</span><span class="pun">(</span><span class="pln">button</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> closeButton </span><span class="pun">=</span><span class="pln"> component</span><span class="pun">.</span><span class="pln">getByText</span><span class="pun">(</span><span class="str">'cancel'</span><span class="pun">)</span><span class="pln">
  fireEvent</span><span class="pun">.</span><span class="pln">click</span><span class="pun">(</span><span class="pln">closeButton</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> div </span><span class="pun">=</span><span class="pln"> component</span><span class="pun">.</span><span class="pln">container</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'.togglableContent'</span><span class="pun">)</span><span class="pln">
  expect</span><span class="pun">(</span><span class="pln">div</span><span class="pun">).</span><span class="pln">toHaveStyle</span><span class="pun">(</span><span class="str">'display: none'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	وتذكر أن التابع <code>getByText</code> الذي استخدمناه سابقًا هو واحد من توابع كثيرة <a data-ss1613551880="1" href="https://testing-library.com/docs/api-queries#queries" rel="external nofollow">للاستقصاء</a> تقدمها المكتبة react-testing-library.
</p>

<h2>
	اختبار النماذج
</h2>

<p>
	لقد استخدمنا للتو الدالة <a data-ss1613551880="1" href="https://testing-library.com/docs/api-events#fireevent" rel="external nofollow">fireEvent</a> في اختباراتنا السابقة لتنفيذ شيفرة نقر الزر.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5254_52" style="">
<span class="kwd">const</span><span class="pln"> button </span><span class="pun">=</span><span class="pln"> component</span><span class="pun">.</span><span class="pln">getByText</span><span class="pun">(</span><span class="str">'show...'</span><span class="pun">)</span><span class="pln">
fireEvent</span><span class="pun">.</span><span class="pln">click</span><span class="pun">(</span><span class="pln">button</span><span class="pun">)</span></pre>

<p>
	نستخدم عمليًا تلك الدالة <code>fireEvent</code> لإنشاء حدث النقر على زر المكوِّن. ويمكننا كذلك محاكاة إدخال نص باستخدامها أيضًا.
</p>

<p>
	لنجر اختبارًا على المكوّن <code>NoteForm</code>. تمثل الشيفرة التالية شيفرة هذا المكوِّن:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5254_54" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> useState </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">NoteForm</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> createNote </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">newNote</span><span class="pun">,</span><span class="pln"> setNewNote</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> handleChange </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    setNewNote</span><span class="pun">(</span><span class="pln">event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">value</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> addNote </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">
    createNote</span><span class="pun">({</span><span class="pln">
      content</span><span class="pun">:</span><span class="pln"> newNote</span><span class="pun">,</span><span class="pln">
      important</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">()</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0.5</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">

    setNewNote</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div className</span><span class="pun">=</span><span class="str">"formDiv"</span><span class="pun">&gt;</span><span class="pln">      
      </span><span class="pun">&lt;</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="typ">Create</span><span class="pln"> a </span><span class="kwd">new</span><span class="pln"> note</span><span class="pun">&lt;/</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">

      </span><span class="pun">&lt;</span><span class="pln">form onSubmit</span><span class="pun">={</span><span class="pln">addNote</span><span class="pun">}&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">input
          value</span><span class="pun">={</span><span class="pln">newNote</span><span class="pun">}</span><span class="pln">
          onChange</span><span class="pun">={</span><span class="pln">handleChange</span><span class="pun">}</span><span class="pln">
        </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">button type</span><span class="pun">=</span><span class="str">"submit"</span><span class="pun">&gt;</span><span class="pln">save</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">NoteForm</span></pre>

<p>
	يعمل النموذج باستدعاء الدالة <code>createNote</code> التي تُمرر إليه كخاصية تحمل تفاصيل الملاحظة الجديدة.
</p>

<p>
	ستبدو شيفرة الاختبار كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5254_56" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> render</span><span class="pun">,</span><span class="pln"> fireEvent </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'@testing-library/react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="str">'@testing-library/jest-dom/extend-expect'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">NoteForm</span><span class="pln"> from </span><span class="str">'./NoteForm'</span><span class="pln">

test</span><span class="pun">(</span><span class="str">'&lt;NoteForm /&gt; updates parent state and calls onSubmit'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> createNote </span><span class="pun">=</span><span class="pln"> jest</span><span class="pun">.</span><span class="pln">fn</span><span class="pun">()</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> component </span><span class="pun">=</span><span class="pln"> render</span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">NoteForm</span><span class="pln"> createNote</span><span class="pun">={</span><span class="pln">createNote</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> input </span><span class="pun">=</span><span class="pln"> component</span><span class="pun">.</span><span class="pln">container</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'input'</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> form </span><span class="pun">=</span><span class="pln"> component</span><span class="pun">.</span><span class="pln">container</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'form'</span><span class="pun">)</span><span class="pln">

  fireEvent</span><span class="pun">.</span><span class="pln">change</span><span class="pun">(</span><span class="pln">input</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
    target</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> value</span><span class="pun">:</span><span class="pln"> </span><span class="str">'testing of forms could be easier'</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> 
  </span><span class="pun">})</span><span class="pln">
  fireEvent</span><span class="pun">.</span><span class="pln">submit</span><span class="pun">(</span><span class="pln">form</span><span class="pun">)</span><span class="pln">

  expect</span><span class="pun">(</span><span class="pln">createNote</span><span class="pun">.</span><span class="pln">mock</span><span class="pun">.</span><span class="pln">calls</span><span class="pun">).</span><span class="pln">toHaveLength</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
  expect</span><span class="pun">(</span><span class="pln">createNote</span><span class="pun">.</span><span class="pln">mock</span><span class="pun">.</span><span class="pln">calls</span><span class="pun">[</span><span class="lit">0</span><span class="pun">][</span><span class="lit">0</span><span class="pun">].</span><span class="pln">content</span><span class="pun">).</span><span class="pln">toBe</span><span class="pun">(</span><span class="str">'testing of forms could be easier'</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	يمكننا محاكاة الكتابة إلى حقول النصوص بإنشاء الحدث <code>change</code> لكل حقل، ثم تعريف كائن يحتوي على النص الذي سيكتب في حقل النص.
</p>

<p>
	سيُرسل النموذج بمحاكاة عمل الحدث <code>submit</code> الذي يستخدم لإرسال نموذج.
</p>

<p>
	تتأكد التعليمة <code>expect</code> للاختبار الأول، أن التابع سيُستدعى عند إرسال النموذج. أما الثانية فستتأكد أن معالج الحدث سيُستدعى بالمعاملات الصحيحة، أي أن محتويات الملاحظة الجديدة التي أنشئت عندما مُلئت حقول النموذج، صحيحة.
</p>

<h2>
	مدى الاختبار
</h2>

<p>
	يمكننا أن نجد بسهولة المدى الذي تغطيه اختباراتنا (<a data-ss1613551880="1" href="https://github.com/facebookincubator/create-react-app/blob/ed5c48c81b2139b4414810e1efe917e04c96ee8d/packages/react-scripts/template/README.md#coverage-reporting" rel="external nofollow">coverage</a>) بتنفيذها من خلال الأمر:
</p>

<pre class="ipsCode">
CI=true npm test -- --coverage
</pre>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="57860" data-unique="dfsu2dvrs" src="https://academy.hsoub.com/uploads/monthly_2021_02/test_covarge_comand_01.png.2fedca364d78633efc46514777cf9907.png" alt="test_covarge_comand_01.png"></p>

<p>
	ستجد تقرير HTML بسيط حول مدى التغطية في المجلد coverage/lcov-report. سيخبرنا التقرير مثلًا عن عدد الأسطر البرمجية التي لم تُختبر في المكوّن:
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="57861" data-unique="z8xndyi2h" src="https://academy.hsoub.com/uploads/monthly_2021_02/test_covarge_html_02.png.3a1384dcc23bd3ad16c8772cfe15a963.png" alt="test_covarge_html_02.png"></p>

<p>
	ستجد شيفرة التطبيق بالكامل ضمن الفرع part5-8 في المستودع المخصص للتطبيق على <a data-ss1613551880="1" href="https://github.com/fullstack-hy2020/part2-notes/tree/part5-8" rel="external nofollow">GitHub</a>.
</p>

<h2>
	التمارين 5.13 - 5.16
</h2>

<h3>
	5.13 اختبارات على قائمة المدونات: الخطوة 1
</h3>

<p>
	اكتب اختبارًا يتحقق أن المكوِّن الذي يعرض المدونة سيصيّر عنوان المدونة ومؤلفها، لكنه لن يصيّر عدد الإعجابات بشكل افتراضي.
</p>

<p>
	اضف أصناف CSS إلى المكوّن للمساعدة في الاختبار عند الحاجة.
</p>

<h3>
	5.14 اختبارات على قائمة المدونات: الخطوة 2
</h3>

<p>
	اكتب اختبارًا يتحقق أن عنوان موقع المدونة (url) وعدد الإعجابات سيظهران عند النقر على الزر الذي يتحكم بإظهار التفاصيل.
</p>

<h3>
	5.14 اختبارات على قائمة المدونات: الخطوة 3
</h3>

<p>
	اكتب اختبارًا يتأكد أن معالج الحدث الذي يُمّرر إلى المكون كخاصية، سيُستدعى مرتين تمامًا عندما يٌنقر الزر <code>like</code> مرتين.
</p>

<h3>
	5.16 اختبارات على قائمة المدونات: الخطوة 4 *
</h3>

<p>
	اكتب اختبارًا لنموذج إنشاء مدونة جديدة. يتحقق الاختبار أن النموذج سيستدعي معالج الحدث الذي يُمرر كخاصية حاملًا التفاصيل عندما تُنشأ مدونة جديدة.
</p>

<p>
	فلو حملت الصفة <code>id</code> للعنصر <code>input</code> مثلًا القيمة "author":
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5254_58" style="">
<span class="tag">&lt;input</span><span class="pln">
  </span><span class="atn">id</span><span class="pun">=</span><span class="atv">'author'</span><span class="pln">
  </span><span class="atn">value</span><span class="pun">=</span><span class="atv">{author}</span><span class="pln">
  </span><span class="atn">onChange</span><span class="pun">={()</span><span class="pln"> </span><span class="tag">=&gt;</span><span class="pln"> {}}
/&gt;</span></pre>

<p>
	يمكنك الوصول إلى محتوى العنصر بالأمر:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5254_60" style="">
<span class="kwd">const</span><span class="pln"> author </span><span class="pun">=</span><span class="pln"> component</span><span class="pun">.</span><span class="pln">container</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'#author'</span><span class="pun">)</span></pre>

<h2>
	اختبارات تكامل الواجهة الأمامية
</h2>

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

<p>
	وحتى هذه اللحظة فإن كل الاختبارات التي أجريناها على الواجهة الأمامية هي اختبارات للأجزاء التي قيّمت صحة الوظيفة التي يقدمها المكوِّن. إن اختبارات الأجزاء مناسبة في بعض الأحيان، لكن لن تكفي في أحيانٍ أخرى أحدث أساليب اختبارات الأجزاء في تقييم عمل التطبيق ككل.
</p>

<p>
	يمكننا أيضًا تنفيذ اختبارات تكامل للواجهة الأمامية. تتحقق هذه الاختبارات من تعاون كل المكونات، وتعتبر أكثر صعوبة من اختبارات الأجزاء لأننا قد نضطر على سبيل المثال، إلى محاكاة البيانات القادمة من الخادم. وقد اخترنا أن نركز على الاختبار المشترك للواجهتين (end to end) لاختبار التطبيق ككل، وسنعمل عليها في الفصل الأخير من هذا القسم.
</p>

<h2>
	اختبارات اللقطات البرمجية
</h2>

<p>
	تقدم Jest بديلًا مختلفًا تمامًا عن الاختبارات التقليدية ويدعى اختبارات اللقطات <a data-ss1613551880="1" href="https://facebook.github.io/jest/docs/en/snapshot-testing.html" rel="external nofollow">snapshot</a>. والميزة الأهم في هذه اللقطات، أنه ليس على المطورين كتابة أية اختبارت بأنفسهم، وكل ما عليهم هو اختيار هذا الاختبار.
</p>

<p>
	يعتمد المبدأ الأساسي لهذه الاختبارات على موازنة شيفرة HTML التي يُعرِّفها المكوّن بعد أن تتغير مع شيفرة HTML قبل التغيير.
</p>

<p>
	إن لاحظ اختبار اللقطات تغييرات في الشيفرة، فسيعتبرها إما وظيفة جديدة أو ثغرة حدثت مصادفةً. كما يبلغ الاختبار المطور إن تغيرت شيفرة HTML في المكوّن، وعلى المطور أن يبلغ Jest أن هذه التغيرات مطلوبة أو غير مطلوبة. فإن كان التغيير في الشيفرة غير متوقع، فالاحتمال كبير أن تكون ثغرة وبالتالي سيدرك المطور المشاكل المحتملة عنها بسهولة بفضل هذا الاختبار.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a data-ss1613551880="1" href="https://fullstackopen.com/en/part5/testing_react_apps" rel="external nofollow">Testing react apps</a> من سلسلة <a data-ss1613551880="1" href="https://fullstackopen.com/en/" rel="external nofollow">Deep Dive Into Modern Web Development</a>
</p>
]]></description><guid isPermaLink="false">1138</guid><pubDate>Wed, 17 Feb 2021 09:07:34 +0000</pubDate></item><item><title>&#x623;&#x647;&#x645;&#x64A;&#x629; &#x645;&#x635;&#x641;&#x648;&#x641;&#x629; &#x627;&#x644;&#x645;&#x643;&#x648;&#x646;&#x627;&#x62A; &#x627;&#x644;&#x623;&#x628;&#x646;&#x627;&#x621; props.Children &#x648;&#x627;&#x644;&#x62D;&#x632;&#x645;&#x629; proptypes &#x641;&#x64A; &#x639;&#x645;&#x644;&#x64A;&#x629; &#x62A;&#x633;&#x62C;&#x64A;&#x644; &#x627;&#x644;&#x62F;&#x62E;&#x648;&#x644; &#x641;&#x64A;  &#x62A;&#x637;&#x628;&#x64A;&#x642; React</title><link>https://academy.hsoub.com/programming/javascript/react/%D8%A3%D9%87%D9%85%D9%8A%D8%A9-%D9%85%D8%B5%D9%81%D9%88%D9%81%D8%A9-%D8%A7%D9%84%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D8%A8%D9%86%D8%A7%D8%A1-propschildren-%D9%88%D8%A7%D9%84%D8%AD%D8%B2%D9%85%D8%A9-proptypes-%D9%81%D9%8A-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D8%B3%D8%AC%D9%8A%D9%84-%D8%A7%D9%84%D8%AF%D8%AE%D9%88%D9%84-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-react-r1137/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_02/602bf28dcabb5_--.png.f3f50f9612f5491bebef66bd76b03b51.png" /></p>

<h2>
	عرض واجهة تسجيل الدخول في الحالات الملائمة
</h2>

<p>
	لنعدل التطبيق بحيث لا تظهر واجهة تسجيل الدخول بشكل افتراضي:
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="57812" data-unique="o52vywru2" src="https://academy.hsoub.com/uploads/monthly_2021_02/ogin_show_01.png.5065d9abdc8416d029d7db4aca814db8.png" alt="ogin_show_01.png"></p>

<p>
	ستظهر الواجهة عندما ينقر المستخدم على الزر "Login":
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="57811" data-unique="ax0k36c30" src="https://academy.hsoub.com/uploads/monthly_2021_02/login_button_02.png.c013fd778a9f80fb6707ccaa8e055e03.png" alt="login_button_02.png"></p>

<p>
	يمكن للمستخدم إغلاق الواجهة أيضًا بالنقر على الزر "Cancel".
</p>

<p>
	سنبدأ بنقل نموذج تسجيل الدخول إلى المكوِّن الخاص به:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9058_7" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">LoginForm</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln">
   handleSubmit</span><span class="pun">,</span><span class="pln">
   handleUsernameChange</span><span class="pun">,</span><span class="pln">
   handlePasswordChange</span><span class="pun">,</span><span class="pln">
   username</span><span class="pun">,</span><span class="pln">
   password
  </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="typ">Login</span><span class="pun">&lt;/</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">

      </span><span class="pun">&lt;</span><span class="pln">form onSubmit</span><span class="pun">={</span><span class="pln">handleSubmit</span><span class="pun">}&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
          username
          </span><span class="pun">&lt;</span><span class="pln">input
            value</span><span class="pun">={</span><span class="pln">username</span><span class="pun">}</span><span class="pln">
            onChange</span><span class="pun">={</span><span class="pln">handleUsernameChange</span><span class="pun">}</span><span class="pln">
          </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
          password
          </span><span class="pun">&lt;</span><span class="pln">input
            type</span><span class="pun">=</span><span class="str">"password"</span><span class="pln">
            value</span><span class="pun">={</span><span class="pln">password</span><span class="pun">}</span><span class="pln">
            onChange</span><span class="pun">={</span><span class="pln">handlePasswordChange</span><span class="pun">}</span><span class="pln">
          </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">button type</span><span class="pun">=</span><span class="str">"submit"</span><span class="pun">&gt;</span><span class="pln">login</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">LoginForm</span></pre>

<p>
	عُرّفت الحالة وكل الدوال المتعلقة بالنموذج خارج المكوِّن وتُمرر إليه كخصائص.
</p>

<p>
	لاحظ كيف أسندت الخصائص إلى المتغيرات بطريقة الإسناد بالتفكيك. ويعني ذلك أننا عوضًا عن كتابة الشيفرة التالية:
</p>

<p>
	pre widget
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9058_9" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">LoginForm</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="typ">Login</span><span class="pun">&lt;/</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">form onSubmit</span><span class="pun">={</span><span class="pln">props</span><span class="pun">.</span><span class="pln">handleSubmit</span><span class="pun">}&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
          username
          </span><span class="pun">&lt;</span><span class="pln">input
            value</span><span class="pun">={</span><span class="pln">props</span><span class="pun">.</span><span class="pln">username</span><span class="pun">}</span><span class="pln">
            onChange</span><span class="pun">={</span><span class="pln">props</span><span class="pun">.</span><span class="pln">handleChange</span><span class="pun">}</span><span class="pln">
            name</span><span class="pun">=</span><span class="str">"username"</span><span class="pln">
          </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="com">// ...</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">button type</span><span class="pun">=</span><span class="str">"submit"</span><span class="pun">&gt;</span><span class="pln">login</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	حيث نحصل فيها على خصائص الكائن<code>prop</code> باستعمال التابع <code>prop.handleSubmit</code>، سنسند الخصائص مباشرة إلى متغيراتها.
</p>

<p>
	إحدى الطرق السريعة في إضافة الوظيفة، هو تعديل الدالة <code>loginForm</code> العائدة للمكوِّن App كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9058_11" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">loginVisible</span><span class="pun">,</span><span class="pln"> setLoginVisible</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="kwd">false</span><span class="pun">)</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> loginForm </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> hideWhenVisible </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> display</span><span class="pun">:</span><span class="pln"> loginVisible </span><span class="pun">?</span><span class="pln"> </span><span class="str">'none'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">''</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> showWhenVisible </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> display</span><span class="pun">:</span><span class="pln"> loginVisible </span><span class="pun">?</span><span class="pln"> </span><span class="str">''</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">'none'</span><span class="pln"> </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">div style</span><span class="pun">={</span><span class="pln">hideWhenVisible</span><span class="pun">}&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setLoginVisible</span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)}&gt;</span><span class="pln">log in</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">div style</span><span class="pun">={</span><span class="pln">showWhenVisible</span><span class="pun">}&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">LoginForm</span><span class="pln">
            username</span><span class="pun">={</span><span class="pln">username</span><span class="pun">}</span><span class="pln">
            password</span><span class="pun">={</span><span class="pln">password</span><span class="pun">}</span><span class="pln">
            handleUsernameChange</span><span class="pun">={({</span><span class="pln"> target </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setUsername</span><span class="pun">(</span><span class="pln">target</span><span class="pun">.</span><span class="pln">value</span><span class="pun">)}</span><span class="pln">
            handlePasswordChange</span><span class="pun">={({</span><span class="pln"> target </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setPassword</span><span class="pun">(</span><span class="pln">target</span><span class="pun">.</span><span class="pln">value</span><span class="pun">)}</span><span class="pln">
            handleSubmit</span><span class="pun">={</span><span class="pln">handleLogin</span><span class="pun">}</span><span class="pln">
          </span><span class="pun">/&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setLoginVisible</span><span class="pun">(</span><span class="kwd">false</span><span class="pun">)}&gt;</span><span class="pln">cancel</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تحتوي حالة المكوِّن App الآن على المتغير المنطقي <code>loginVisible</code> الذي سيقرر أتعرض واجهة تسجيل الدخول للمستخدم أم لا. تتبدل قيمة <code>loginVisible</code> باستعمال زرين، ولكل منهما معالج الحدث الخاص به والمعرّف مباشرة داخل المكون:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_9058_13" style="">
<span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="tag">=&gt;</span><span class="pln"> setLoginVisible(true)}&gt;log in</span><span class="tag">&lt;/button&gt;</span><span class="pln">

</span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="tag">=&gt;</span><span class="pln"> setLoginVisible(false)}&gt;cancel</span><span class="tag">&lt;/button&gt;</span></pre>

<p>
	تُحدَّد إمكانية ظهور المكوِّن بتنسيقه <a data-ss1613492867="1" href="ttps://fullstackopen.com/en/part2/adding_styles_to_react_app#inline-styles" rel="external nofollow">ضمن السياق</a>، حيث سيختفي المكوًن إن كانت قيمة الخاصية <a data-ss1613492867="1" href="https://developer.mozilla.org/en-US/docs/Web/CSS/display" rel="external nofollow">display</a> هي (none).
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9058_15" style="">
<span class="kwd">const</span><span class="pln"> hideWhenVisible </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> display</span><span class="pun">:</span><span class="pln"> loginVisible </span><span class="pun">?</span><span class="pln"> </span><span class="str">'none'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">''</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> showWhenVisible </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> display</span><span class="pun">:</span><span class="pln"> loginVisible </span><span class="pun">?</span><span class="pln"> </span><span class="str">''</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">'none'</span><span class="pln"> </span><span class="pun">}</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">div style</span><span class="pun">={</span><span class="pln">hideWhenVisible</span><span class="pun">}&gt;</span><span class="pln">
  </span><span class="com">// button</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">

</span><span class="pun">&lt;</span><span class="pln">div style</span><span class="pun">={</span><span class="pln">showWhenVisible</span><span class="pun">}&gt;</span><span class="pln">
  </span><span class="com">// button</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span></pre>

<p>
	لاحظ أننا استخدمنا مجددًا العامل"؟" ثلاثي المعاملات. إن كان المتغير <code>loginVisible</code> "صحيحًا"، ستحمل قاعدة CSS للمكوِّن القيمة التالية:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_9058_17" style="">
<span class="pln">display</span><span class="pun">:</span><span class="pln"> </span><span class="str">'none'</span><span class="pun">;</span></pre>

<p>
	وإن كان <code>loginVisible</code> "خاطئًا"، لن تحمل الخاصية <code>display</code> أية قيمة تتعلق بعرض المكوِّن.
</p>

<h2>
	المكونات الأبناء (أو المصفوفة props.children)
</h2>

<p>
	يُعتبر منطق الشيفرة التي تتحكم بظهور نموذج تسجيل الدخول مستقل بذاته، لهذا من الأجدى أن ننقلها إلى مكوّن جديد خاص بها.
</p>

<p>
	هدفنا حاليًا إضافة مكوِّن متبدّل (Togglable) يُستخدم بالطريقة التالية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_9058_19" style="">
<span class="tag">&lt;Togglable</span><span class="pln"> </span><span class="atn">buttonLabel</span><span class="pun">=</span><span class="atv">'login'</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;LoginForm</span><span class="pln">
    </span><span class="atn">username</span><span class="pun">=</span><span class="atv">{username}</span><span class="pln">
    </span><span class="atn">password</span><span class="pun">=</span><span class="atv">{password}</span><span class="pln">
    </span><span class="atn">handleUsernameChange</span><span class="pun">=</span><span class="atv">{({</span><span class="pln"> </span><span class="atn">target</span><span class="pln"> }) </span><span class="tag">=&gt;</span><span class="pln"> setUsername(target.value)}
    handlePasswordChange={({ target }) =&gt; setPassword(target.value)}
    handleSubmit={handleLogin}
  /&gt;
</span><span class="tag">&lt;/Togglable&gt;</span></pre>

<p>
	تختلف طريقة استخدام المكوِّن قليلًا عن المكوٍّنات السابقة. فللمكوّن معرفات بداية ونهاية تحيط بمكوّن <code>LoginForm</code>. تصطلح React على تسمية المكوًّن <code>LoginForm</code> بالمكوِّن الإبن للمكوِّن <code>Togglable</code>.
</p>

<p>
	يمكننا إضافة عناصر React بين معرفي البداية والنهاية للمكوِّن <code>Togglable</code> كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_9058_21" style="">
<span class="tag">&lt;Togglable</span><span class="pln"> </span><span class="atn">buttonLabel</span><span class="pun">=</span><span class="atv">"reveal"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;p&gt;</span><span class="pln">this line is at start hidden</span><span class="tag">&lt;/p&gt;</span><span class="pln">
  </span><span class="tag">&lt;p&gt;</span><span class="pln">also this is hidden</span><span class="tag">&lt;/p&gt;</span><span class="pln">
</span><span class="tag">&lt;/Togglable&gt;</span></pre>

<p>
	الشيفرة التالية هي شيفرة المكوِّن <code>Togglable</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9058_23" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> useState </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Togglable</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">visible</span><span class="pun">,</span><span class="pln"> setVisible</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="kwd">false</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> hideWhenVisible </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> display</span><span class="pun">:</span><span class="pln"> visible </span><span class="pun">?</span><span class="pln"> </span><span class="str">'none'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">''</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> showWhenVisible </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> display</span><span class="pun">:</span><span class="pln"> visible </span><span class="pun">?</span><span class="pln"> </span><span class="str">''</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">'none'</span><span class="pln"> </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> toggleVisibility </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    setVisible</span><span class="pun">(!</span><span class="pln">visible</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div style</span><span class="pun">={</span><span class="pln">hideWhenVisible</span><span class="pun">}&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">toggleVisibility</span><span class="pun">}&gt;{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">buttonLabel</span><span class="pun">}&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div style</span><span class="pun">={</span><span class="pln">showWhenVisible</span><span class="pun">}&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">children</span><span class="pun">}</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">toggleVisibility</span><span class="pun">}&gt;</span><span class="pln">cancel</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">Togglable</span></pre>

<p>
	إن الجزء الجديد والمهم في الشيفرة هي الخاصية <a data-ss1613492867="1" href="https://reactjs.org/docs/glossary.html#propschildren" rel="external nofollow">props.children</a>، والتي يستخدم في الإشارة إلى المكوِّنات الأبناء لمكوِّن، والتي تمثل عناصر React الموجودة ضمن معرفي بداية ونهاية المكوّن.
</p>

<p>
	ستصيّر الآن المكونات الأبناء بالشيفرة ذاتها التي تصيّر المكون الأب:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_9058_25" style="">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">style</span><span class="pun">={</span><span class="pln">showWhenVisible</span><span class="pun">}</span><span class="tag">&gt;</span><span class="pln">
  {props.children}
  </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">onClick</span><span class="pun">={</span><span class="pln">toggleVisibility</span><span class="pun">}</span><span class="tag">&gt;</span><span class="pln">cancel</span><span class="tag">&lt;/button&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	وعلى خلاف الخصائص الاعتيادية التي رأيناها سابقًا يضاف "الأبناء" تلقائيًا من قبل React وتكون موجودة دائمًا.
</p>

<p>
	لو عرّفنا مكوّنًا له معرف نهاية تلقائي "&lt;/" كالمكوِّن التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_9058_27" style="">
<span class="tag">&lt;Note</span><span class="pln">
  </span><span class="atn">key</span><span class="pun">=</span><span class="atv">{note.id}</span><span class="pln">
  </span><span class="atn">note</span><span class="pun">=</span><span class="atv">{note}</span><span class="pln">
  </span><span class="atn">toggleImportance</span><span class="pun">=</span><span class="atv">{()</span><span class="pln"> </span><span class="tag">=&gt;</span><span class="pln"> toggleImportanceOf(note.id)}
/&gt;</span></pre>

<p>
	ستشكل الخاصية <code>props.children</code> مصفوفة فارغة.
</p>

<p>
	يمكن إعادة استعمال المكوِّن <code>togglable</code> لإضافة خاصية العرض والإخفاء للنموذج الذي استخدمناه في إنشاء ملاحظة جديدة.
</p>

<p>
	قبل أن نفعل ذلك، لننقل شيفرة نموذج إنشاء الملاحظات الجديدة إلى مكوِّن مستقل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9058_29" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">NoteForm</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> onSubmit</span><span class="pun">,</span><span class="pln"> handleChange</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="typ">Create</span><span class="pln"> a </span><span class="kwd">new</span><span class="pln"> note</span><span class="pun">&lt;/</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">

      </span><span class="pun">&lt;</span><span class="pln">form onSubmit</span><span class="pun">={</span><span class="pln">onSubmit</span><span class="pun">}&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">input
          value</span><span class="pun">={</span><span class="pln">value</span><span class="pun">}</span><span class="pln">
          onChange</span><span class="pun">={</span><span class="pln">handleChange</span><span class="pun">}</span><span class="pln">
        </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">button type</span><span class="pun">=</span><span class="str">"submit"</span><span class="pun">&gt;</span><span class="pln">save</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سنعرّف تاليًا مكوِّن النموذج داخل المكوّن <code>Togglable</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9058_31" style="">
<span class="pun">&lt;</span><span class="typ">Togglable</span><span class="pln"> buttonLabel</span><span class="pun">=</span><span class="str">"new note"</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="typ">NoteForm</span><span class="pln">
    onSubmit</span><span class="pun">={</span><span class="pln">addNote</span><span class="pun">}</span><span class="pln">
    value</span><span class="pun">={</span><span class="pln">newNote</span><span class="pun">}</span><span class="pln">
    handleChange</span><span class="pun">={</span><span class="pln">handleNoteChange</span><span class="pun">}</span><span class="pln">
  </span><span class="pun">/&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="typ">Togglable</span><span class="pun">&gt;</span></pre>

<p>
	يمكنك إيجاد الشيفرة الكاملة لتطبيقنا الحالي ضمن الفرع part5-4 في المستودع المخصص للتطبيق على <a data-ss1613492867="1" href="https://github.com/fullstack-hy2020/part2-notes/tree/part5-4" rel="external nofollow">GitHub</a>.
</p>

<h2>
	حالة النماذج
</h2>

<p>
	تتواجد حالة التطبيق في المكون الأعلى App. حيث ينص توثيق React على <a data-ss1613492867="1" href="https://reactjs.org/docs/lifting-state-up.html" rel="external nofollow">ما يلي</a> بخصوص مكان تواجد الحالة:
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p>
		عادة ما تحتاج عدة مكوِّنات أن تعكس نفس التغيرات في الحالة. لهذا نوصي بنقل الحالة المشتركة لتكون داخل المكوّن الأب الأقرب إلى كل المكوِّنات الأبناء.
	</p>
</blockquote>

<p>
	لو فكرنا قليلًا بحالة النماذج التي يضمها التطبيق، فلن يحتاج المكوّن App، على سبيل المثال، محتوى الملاحظة الجديدة قبل إنشائها. لذلك يمكننا بالمثل نقل حالة النماذج إلى مكوِّن خاص بها.
</p>

<p>
	سيتغيّر مكِّون الملاحظة إلى الشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9058_33" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">useState</span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln"> 

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">NoteForm</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> createNote </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">newNote</span><span class="pun">,</span><span class="pln"> setNewNote</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln"> 

  </span><span class="kwd">const</span><span class="pln"> handleChange </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    setNewNote</span><span class="pun">(</span><span class="pln">event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">value</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> addNote </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">
    createNote</span><span class="pun">({</span><span class="pln">
      content</span><span class="pun">:</span><span class="pln"> newNote</span><span class="pun">,</span><span class="pln">
      important</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">()</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0.5</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">

    setNewNote</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="typ">Create</span><span class="pln"> a </span><span class="kwd">new</span><span class="pln"> note</span><span class="pun">&lt;/</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">

      </span><span class="pun">&lt;</span><span class="pln">form onSubmit</span><span class="pun">={</span><span class="pln">addNote</span><span class="pun">}&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">input
          value</span><span class="pun">={</span><span class="pln">newNote</span><span class="pun">}</span><span class="pln">
          onChange</span><span class="pun">={</span><span class="pln">handleChange</span><span class="pun">}</span><span class="pln">
        </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">button type</span><span class="pun">=</span><span class="str">"submit"</span><span class="pun">&gt;</span><span class="pln">save</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">NoteForm</span></pre>

<p>
	نُقلت صفة الحالة <code>newNote</code> ومعالج الحدث المسؤول عن تغييرها من المكوِّن App إلى المكوِّن المسؤول عن نموذج الملاحظات. وبقيت فقط الخاصية <code>createNote</code> وهي دالة يستدعيها النموذج عندما تُنشأ ملاحظة جديدة.
</p>

<p>
	سيغدو المكوّن أبسط بعد إزالة الحالة <code>newNote</code> ومعالج الحدث المرتبط بها. ستستقبل الدالة <code>addNote</code> التي تنشئ ملاحظة جديدة هذه الملاحظة كوسيط، وهذه الدالة هي الصفة الوحيدة التي أرسلناها إلى النموذج:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9058_35" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> addNote </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">noteObject</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    noteService
      </span><span class="pun">.</span><span class="pln">create</span><span class="pun">(</span><span class="pln">noteObject</span><span class="pun">)</span><span class="pln">
      </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">returnedNote </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        setNotes</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">concat</span><span class="pun">(</span><span class="pln">returnedNote</span><span class="pun">))</span><span class="pln">
      </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> noteForm </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">Togglable</span><span class="pln"> buttonLabel</span><span class="pun">=</span><span class="str">'new note'</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">NoteForm</span><span class="pln"> createNote</span><span class="pun">={</span><span class="pln">addNote</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="typ">Togglable</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">

  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يمكن أن نكرر هذه العملية على نموذج تسجيل الدخول، لكننا سنترك ذلك للتمارين الإختيارية.
</p>

<p>
	يمكنك إيجاد شيفرة التطبيق في الفرع part5-5 على <a data-ss1613492867="1" href="https://github.com/fullstack-hy2020/part2-notes/tree/part5-5" rel="external nofollow">GitHub</a>.
</p>

<h2>
	إنشاء مراجع إلى المكوِّنات باستعمال ref
</h2>

<p>
	جميع الإضافات التي أجريت على التطبيق جيدة، لكن هناك ناحية واحدة يمكن تحسينها.
</p>

<p>
	من المنطقي إخفاء نموذج إضافة الملاحظات بعد أن ننشئ الملاحظة الجديدة، لأن النموذج سيبقى ظاهرًا في الوضع الحالي. لكن هناك مشكلة صغيرة في ذلك، فمن يتحكم بعرض النماذج هو المتغير <code>visible</code> الموجود داخل المكوِّن <code>Tooglable</code>. فما هي الطريقة التي تمكننا من الوصول إليه، وهو خارج مكوّن النموذج؟
</p>

<p>
	هناك طرق عديدة لإغلاق النموذج من المكوّن الأب، لكننا سنستعمل آلية المرجع <a data-ss1613492867="1" href="https://reactjs.org/docs/refs-and-the-dom.html" rel="external nofollow">ref</a> الخاصة بالمكتبة React والتي تؤمن مرجعًا إلى المكوِّن.
</p>

<p>
	لنعدّل المكوّن App ليصبح كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9058_37" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> useState</span><span class="pun">,</span><span class="pln"> useRef </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> noteFormRef </span><span class="pun">=</span><span class="pln"> useRef</span><span class="pun">()</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> noteForm </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">Togglable</span><span class="pln"> buttonLabel</span><span class="pun">=</span><span class="str">'new note'</span><span class="pln"> ref</span><span class="pun">={</span><span class="pln">noteFormRef</span><span class="pun">}&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">NoteForm</span><span class="pln"> createNote</span><span class="pun">={</span><span class="pln">addNote</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="typ">Togglable</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">

  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يستخدم الخطاف <a data-ss1613492867="1" href="https://reactjs.org/docs/hooks-reference.html#useref" rel="external nofollow">useRef</a> لإنشاء مرجع إلى المتغير <code>noteFormRef</code> ويسند إلى المكوّن <code>Togglable</code> الذي يحتوي نموذج إنشاء ملاحظة. وبالتالي سيعمل المتغير <code>noteFormRef</code> كمرجع إلى المكوّن. يضمن الخطاف أن يبقى المرجع كما هو عند إعادة تصيير المكوِّن.
</p>

<p>
	عدّلنا أيضًا المكون <code>Togglable</code> ليصبح على الشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9058_39" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> useState</span><span class="pun">,</span><span class="pln"> useImperativeHandle </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Togglable</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">React</span><span class="pun">.</span><span class="pln">forwardRef</span><span class="pun">((</span><span class="pln">props</span><span class="pun">,</span><span class="pln"> ref</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">visible</span><span class="pun">,</span><span class="pln"> setVisible</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="kwd">false</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> hideWhenVisible </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> display</span><span class="pun">:</span><span class="pln"> visible </span><span class="pun">?</span><span class="pln"> </span><span class="str">'none'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">''</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> showWhenVisible </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> display</span><span class="pun">:</span><span class="pln"> visible </span><span class="pun">?</span><span class="pln"> </span><span class="str">''</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">'none'</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> toggleVisibility </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    setVisible</span><span class="pun">(!</span><span class="pln">visible</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  useImperativeHandle</span><span class="pun">(</span><span class="pln">ref</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">    
      </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">      
          toggleVisibility    
      </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div style</span><span class="pun">={</span><span class="pln">hideWhenVisible</span><span class="pun">}&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">toggleVisibility</span><span class="pun">}&gt;{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">buttonLabel</span><span class="pun">}&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div style</span><span class="pun">={</span><span class="pln">showWhenVisible</span><span class="pun">}&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">children</span><span class="pun">}</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">toggleVisibility</span><span class="pun">}&gt;</span><span class="pln">cancel</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">Togglable</span></pre>

<p>
	تُغلَّف الدالة التي تنشئ المكوّن داخل استدعاء الدالة <a data-ss1613492867="1" href="https://wiki.hsoub.com/React/react_api#React.forwardRef" rel="external">forwardRef</a>، وبالتالي سيتمكن المكوّن من الوصول إلى المرجع الذي أسند إليه. يستخدم المكوِّن الخطاف <a data-ss1613492867="1" href="https://wiki.hsoub.com/React/hooks_reference#useImperativeHandle" rel="external">useImperativeHandle</a> ليجعل الدالة <code>toggleVisibility</code> متاحة خارج إطار المكوِّن.
</p>

<p>
	سنتمكن الآن من إخفاء النموذج بتنفيذ الأمر <code>()noteFormRef.current.toggleVisibility</code> بعد أن تُنشأ الملاحظة الجديدة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9058_41" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> addNote </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">noteObject</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    noteFormRef</span><span class="pun">.</span><span class="pln">current</span><span class="pun">.</span><span class="pln">toggleVisibility</span><span class="pun">()</span><span class="pln">
    noteService
      </span><span class="pun">.</span><span class="pln">create</span><span class="pun">(</span><span class="pln">noteObject</span><span class="pun">)</span><span class="pln">
      </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">returnedNote </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">     
        setNotes</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">concat</span><span class="pun">(</span><span class="pln">returnedNote</span><span class="pun">))</span><span class="pln">
      </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ولكي نلخص ما مضى، فإن الدالة <a data-ss1613492867="1" href="https://wiki.hsoub.com/React/hooks_reference#useImperativeHandle" rel="external">useImperativeHandle</a> هي خطاف يستخدم لتعريف دوال داخل المكوِّن يمكن استدعاؤها من خارجه.
</p>

<p>
	تنجح هذه الحيلة في تغيير حالة المكوِّن، لكنها مزعجة قليلًا. وقد كان بالإمكان إنجاز الوظيفة نفسها وبأسلوب أوضح مستخدمين طريقة المكوّنات المعتمدة على الأصناف التي اعتمدتها React القديمة. سنلقي نظرة على هذه الأصناف في القسم 7. إذًا فهي الحالة الوحيدة التي يكون فيها استخدام خطافات React أقل وضوحًا من مكوِّنات الأصناف.
</p>

<p>
	تستخدم المراجع في <a data-ss1613492867="1" href="https://wiki.hsoub.com/React/refs_and_the_dom" rel="external">عدة حالات أخرى</a> مختلفة غير الوصول إلى مكوِّنات React.
</p>

<p>
	يمكنك أن تجد شيفرة التطبيق بأكملها ضمن الفرع part5-6 في المستودع الخاص بالتطبيق على <a data-ss1613492867="1" href="https://github.com/fullstack-hy2020/part2-notes/tree/part5-6" rel="external nofollow">GitHub</a>
</p>

<h2>
	نقطة أخرى حول المكوّنات
</h2>

<p>
	عندما نعرّف مكوّنًا في React كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9058_43" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Togglable</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">...</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ونستخدمه بالشكل:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_9058_45" style="">
<span class="tag">&lt;div&gt;</span><span class="pln">
  </span><span class="tag">&lt;Togglable</span><span class="pln"> </span><span class="atn">buttonLabel</span><span class="pun">=</span><span class="atv">"1"</span><span class="pln"> </span><span class="atn">ref</span><span class="pun">=</span><span class="atv">{togglable1}</span><span class="tag">&gt;</span><span class="pln">
    first
  </span><span class="tag">&lt;/Togglable&gt;</span><span class="pln">

  </span><span class="tag">&lt;Togglable</span><span class="pln"> </span><span class="atn">buttonLabel</span><span class="pun">=</span><span class="atv">"2"</span><span class="pln"> </span><span class="atn">ref</span><span class="pun">=</span><span class="atv">{togglable2}</span><span class="tag">&gt;</span><span class="pln">
    second
  </span><span class="tag">&lt;/Togglable&gt;</span><span class="pln">

  </span><span class="tag">&lt;Togglable</span><span class="pln"> </span><span class="atn">buttonLabel</span><span class="pun">=</span><span class="atv">"3"</span><span class="pln"> </span><span class="atn">ref</span><span class="pun">=</span><span class="atv">{togglable3}</span><span class="tag">&gt;</span><span class="pln">
    third
  </span><span class="tag">&lt;/Togglable&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	سنكون قد أنشأنا ثلاثة مكوّنات منفصلة ولكل منها حالته المستقلة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-ss1613492867="1" href="https://academy.hsoub.com/uploads/monthly_2021_02/component_states_03.png.ffb6f06d0d1e0d973889ae06d97cbdc2.png" data-fileid="57806" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="57806" data-unique="vnvtn77n1" src="https://academy.hsoub.com/uploads/monthly_2021_02/component_states_03.png.ffb6f06d0d1e0d973889ae06d97cbdc2.png" alt="component_states_03.png"></a>
</p>

<p>
	وتستخدم الصفة <code>ref</code> لإسناد مرجع لكل مكوّن ضمن المتغيرات <code>togglable1</code> و<code>togglable2</code> و<code>togglable3</code>.
</p>

<h2>
	التمارين 5.5 - 5.10
</h2>

<h3>
	5.5 واجهة أمامية لقائمة المدونات: الخطوة 5
</h3>

<p>
	غيّر نموذج إنشاء مدوّنة لكي يعرض عند الحاجة فقط. استخدم الأسلوب الذي اعتمدناه في بداية هذا الفصل. يمكنك إن أردت استعمال المكوّن <code>Togglable</code> الذي أنشأناه سابقًا.
</p>

<p>
	يجب أن لا يظهر النموذج بشكل افتراضي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-ss1613492867="1" href="https://academy.hsoub.com/uploads/monthly_2021_02/form_invisible_04.png.00b5f13aa44588380b2abf889eac8189.png" data-fileid="57809" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="57809" data-unique="2jc2b5tet" src="https://academy.hsoub.com/uploads/monthly_2021_02/form_invisible_04.png.00b5f13aa44588380b2abf889eac8189.png" alt="form_invisible_04.png"></a>
</p>

<p>
	يظهر النموذج بالنقر على الزر "new note":
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="57810" data-unique="51q73uwfc" src="https://academy.hsoub.com/uploads/monthly_2021_02/form_visible_05..png.db625e053a6bd8b4e7164720e4b3daba.png" alt="form_visible_05..png"></p>

<p>
	يختفي النموذج عند إنشاء مدونة جديدة.
</p>

<h3>
	5.6 واجهة أمامية لقائمة المدونات: الخطوة 6
</h3>

<p>
	افصل شيفرة نموذج إنشاء مدونة جديدة وضعها في مكوِّنها الخاص (إن لم تكن قد فعلت ذلك مسبقًا)، ثم انقل كل الحالات التي يتطلبها إنشاء مدونة جديدة إلى هذا المكوِّن.
</p>

<p>
	يجب أن يعمل المكوِّن بشكل مشابه للمكوِّن <code>NoteForm</code> الذي أنشأناه سابقًا في هذا الفصل.
</p>

<h3>
	5.7 واجهة أمامية لقائمة المدونات: الخطوة 7 *
</h3>

<p>
	لنضف زرًا إلى كل مدونة ليتحكم بإظهار كل تفاصيل المدونة أو عدم إظهارها. حيث تظهر كل التفاصيل بالنقر على الزر
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="57815" data-unique="5hxllsd9w" src="https://academy.hsoub.com/uploads/monthly_2021_02/show_all_details_06.png.4d8495247c6b84fae2e5171b469ac758.png" alt="show_all_details_06.png"></p>

<p>
	وتختفي التفاصيل بالنقر على الزر ثانيةً.
</p>

<p>
	لا حاجة أن ينفذ الزر "like" أي شيء حاليًا.
</p>

<p>
	يستخدم التطبيق في الصورة السابقة بعض قواعد CSS لتحسين المظهر، ومن السهل القيام بذلك إن أدرجت قواعد التنسيق <a data-ss1613492867="1" href="https://fullstackopen.com/en/part2/adding_styles_to_react_app#inline-styles" rel="external nofollow">ضمن السياق</a>، كما فعلنا في القسم 2.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9058_47" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Blog</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> blog </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> blogStyle </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    paddingTop</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln">
    paddingLeft</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln">
    border</span><span class="pun">:</span><span class="pln"> </span><span class="str">'solid'</span><span class="pun">,</span><span class="pln">
    borderWidth</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
    marginBottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div style</span><span class="pun">={</span><span class="pln">blogStyle</span><span class="pun">}&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">blog</span><span class="pun">.</span><span class="pln">title</span><span class="pun">}</span><span class="pln"> </span><span class="pun">{</span><span class="pln">blog</span><span class="pun">.</span><span class="pln">author</span><span class="pun">}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="com">// ...</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">)}</span></pre>

<p>
	<strong>ملاحظة</strong>: على الرغم من أن الوظيفة التي أضيفت هنا مطابقة تمامًا للوظيفة التي ينفذها بها المكوِّن<code>Toggleable</code>، لا يمكنك استخدام هذا المكوِّن مباشرة لتحقيق المطلوب في هذا التمرين. سيكون الحل الأسهل بإضافة حالة إلى المنشور تتحكم بالنموذج الذي يعرضه.
</p>

<h3>
	5.8 واجهة أمامية لقائمة المدونات: الخطوة 8 *
</h3>

<p>
	اضف وظيفةً لزر الاعجابات. يزداد عدد الإعجابات بإرسال طلب HTTP-PUT إلى عنوان المدونة الفريد في الواجهة الخلفية. وطالما أن العملية في الواجهة الخلفية ستستبدل المنشور كاملًا، عليك إرسال كل حقول المنشور ضمن جسم الطلب.
</p>

<p>
	فلو أردت إضافة إعجاب إلى المنشور التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9058_49" style="">
<span class="pun">{</span><span class="pln">
  _id</span><span class="pun">:</span><span class="pln"> </span><span class="str">"5a43fde2cbd20b12a2c34e91"</span><span class="pun">,</span><span class="pln">
  user</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    _id</span><span class="pun">:</span><span class="pln"> </span><span class="str">"5a43e6b6c37f3d065eaaa581"</span><span class="pun">,</span><span class="pln">
    username</span><span class="pun">:</span><span class="pln"> </span><span class="str">"mluukkai"</span><span class="pun">,</span><span class="pln">
    name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Matti Luukkainen"</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  likes</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln">
  author</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Joel Spolsky"</span><span class="pun">,</span><span class="pln">
  title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"The Joel Test: 12 Steps to Better Code"</span><span class="pun">,</span><span class="pln">
  url</span><span class="pun">:</span><span class="pln"> </span><span class="str">"https://www.joelonsoftware.com/2000/08/09/the-joel-test-12-steps-to-better-code/"</span><span class="pln">
</span><span class="pun">},</span></pre>

<p>
	عليك إرسال طلب HTTP-PUT إلى العنوان api/blogs/5a43fde2cbd20b12a2c34e91/، يتضمن البيانات التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9058_51" style="">
<span class="pun">{</span><span class="pln">
  user</span><span class="pun">:</span><span class="pln"> </span><span class="str">"5a43e6b6c37f3d065eaaa581"</span><span class="pun">,</span><span class="pln">
  likes</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
  author</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Joel Spolsky"</span><span class="pun">,</span><span class="pln">
  title</span><span class="pun">:</span><span class="pln"> </span><span class="str">"The Joel Test: 12 Steps to Better Code"</span><span class="pun">,</span><span class="pln">
  url</span><span class="pun">:</span><span class="pln"> </span><span class="str">"https://www.joelonsoftware.com/2000/08/09/the-joel-test-12-steps-to-better-code/"</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	<strong>تحذير من جديد</strong>: إن لاحظت أنك تستخدم await/async مع then فتأكد أنك سترتكب خطأً ما. استخدم أحد الأسلوبين وليس كلاهما في الوقت ذاته.
</p>

<h3>
	5.9 واجهة أمامية لقائمة المدونات: الخطوة 9 *
</h3>

<p>
	عدّل التطبيق ليرتب المنشورات وفقًا لعدد الإعجابات التي تحملها. يمكن ترتيب المنشورات باستخدام تابع المصفوفات <a data-ss1613492867="1" href="https://wiki.hsoub.com/JavaScript/Array/sort" rel="external">sort</a>.
</p>

<h3>
	5.10 واجهة أمامية لقائمة المدونات: الخطوة 10 *
</h3>

<p>
	أضف زرًا لحذف منشور. وأضف أيضًا وسيلة لحذف المنشورات في الواجهة الخلفية.
</p>

<p>
	قد يبدو تطبيقك مشابهًا للشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-ss1613492867="1" href="https://academy.hsoub.com/uploads/monthly_2021_02/blog_delete_07.png.bda57208d10f20946e2421d298d564e0.png" data-fileid="57805" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="57805" data-unique="io70imyso" src="https://academy.hsoub.com/uploads/monthly_2021_02/blog_delete_07.png.bda57208d10f20946e2421d298d564e0.png" alt="blog_delete_07.png"></a>
</p>

<p>
	يمكنك إظهار رسالة لتأكيد الحذف باستخدام الدالة <a data-ss1613492867="1" href="https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm" rel="external nofollow">window.confirm</a>.
</p>

<p>
	أظهر زر حذف المنشور إذا كان المستخدم الحالي للتطبيق هو من أنشأ هذا المنشور.
</p>

<h2>
	الحزمة PropTypes والخصائص النمطية
</h2>

<p>
	يفترض المكوِّن <code>Togglable</code> أنه سيحصل على النص الذي سيظهر على الزر عبر الخاصية <code>buttonLabel</code>، فلو نسينا تحديد ذلك في المكوِّن:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_9058_54" style="">
<span class="tag">&lt;Togglable&gt;</span><span class="pln"> buttonLabel forgotten... </span><span class="tag">&lt;/Togglable&gt;</span></pre>

<p>
	سيعمل التطبيق، لكن سيصيّر المتصفح الزر الذي لا يحمل نصًا.
</p>

<p>
	لذلك قد نرغب أن نجعل وجود قيمة للنص الذي سيظهر كعنوان على الزر أمرًا إجباريًا عند استخدام المكوِّن <code>Togglable</code>. يمكننا تحديد الخصائص المتوقعة والضرورية (الخصائص النمطية) باستخدام الحزمة <a data-ss1613492867="1" href="https://github.com/facebook/prop-types" rel="external nofollow">prop-types</a>. لنثبت الحزمة إذًا
</p>

<pre class="ipsCode">
npm install prop-types
</pre>

<p>
	يمكننا تحدد الخاصية <code>buttonLabel</code> كخاصية إجبارية أو كخاصية نصية لازمة كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9058_56" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">PropTypes</span><span class="pln"> from </span><span class="str">'prop-types'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Togglable</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">React</span><span class="pun">.</span><span class="pln">forwardRef</span><span class="pun">((</span><span class="pln">props</span><span class="pun">,</span><span class="pln"> ref</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ..</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

</span><span class="typ">Togglable</span><span class="pun">.</span><span class="pln">propTypes </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  buttonLabel</span><span class="pun">:</span><span class="pln"> </span><span class="typ">PropTypes</span><span class="pun">.</span><span class="pln">string</span><span class="pun">.</span><span class="pln">isRequired
</span><span class="pun">}</span></pre>

<p>
	ستعرض الطرفية رسالة الخطأ التالية إذا لم نحدد قيمة الخاصية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-ss1613492867="1" href="https://academy.hsoub.com/uploads/monthly_2021_02/console_prop_undef_08.png.492131dbcecc3a35dbee282efbf66c5c.png" data-fileid="57808" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="57808" data-unique="uz8tkn0er" src="https://academy.hsoub.com/uploads/monthly_2021_02/console_prop_undef_08.png.492131dbcecc3a35dbee282efbf66c5c.png" alt="console_prop_undef_08.png"></a>
</p>

<p>
	سيعمل التطبيق، فلا يمكن إجبارنا على تحديد الخصائص سوى تعريفات الخصائص النمطية PropTypes. لكن تذكر أن ترك رسائل غير مقروءة على طرفية المتصفح، هو أمر غير مهني على الإطلاق.
</p>

<p>
	لنعرِّف خصائص نمطية للمكوِّن <code>LoginForm</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9058_58" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">PropTypes</span><span class="pln"> from </span><span class="str">'prop-types'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">LoginForm</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln">
   handleSubmit</span><span class="pun">,</span><span class="pln">
   handleUsernameChange</span><span class="pun">,</span><span class="pln">
   handlePasswordChange</span><span class="pun">,</span><span class="pln">
   username</span><span class="pun">,</span><span class="pln">
   password
  </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ...</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

</span><span class="typ">LoginForm</span><span class="pun">.</span><span class="pln">propTypes </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  handleSubmit</span><span class="pun">:</span><span class="pln"> </span><span class="typ">PropTypes</span><span class="pun">.</span><span class="pln">func</span><span class="pun">.</span><span class="pln">isRequired</span><span class="pun">,</span><span class="pln">
  handleUsernameChange</span><span class="pun">:</span><span class="pln"> </span><span class="typ">PropTypes</span><span class="pun">.</span><span class="pln">func</span><span class="pun">.</span><span class="pln">isRequired</span><span class="pun">,</span><span class="pln">
  handlePasswordChange</span><span class="pun">:</span><span class="pln"> </span><span class="typ">PropTypes</span><span class="pun">.</span><span class="pln">func</span><span class="pun">.</span><span class="pln">isRequired</span><span class="pun">,</span><span class="pln">
  username</span><span class="pun">:</span><span class="pln"> </span><span class="typ">PropTypes</span><span class="pun">.</span><span class="pln">string</span><span class="pun">.</span><span class="pln">isRequired</span><span class="pun">,</span><span class="pln">
  password</span><span class="pun">:</span><span class="pln"> </span><span class="typ">PropTypes</span><span class="pun">.</span><span class="pln">string</span><span class="pun">.</span><span class="pln">isRequired
</span><span class="pun">}</span></pre>

<p>
	إن كان نمط الخاصية الممررة خاطئًا، كأن نعرف مثلًا الخاصية <code>handleSubmit</code> كنص، سيتسبب ذلك برسالة التحذير التالية:
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="57813" data-unique="q2igflkqq" src="https://academy.hsoub.com/uploads/monthly_2021_02/prop_undef_war_09.png.e5806c42c71713f0059e61789ff93b0a.png" alt="prop_undef_war_09.png"></p>

<h2>
	المدقق ESlint
</h2>

<p>
	هيئنا في القسم 3 مدقق تنسيق الشيفرة <a data-ss1613492867="1" href="https://fullstackopen.com/en/part3/validation_and_es_lint#lint" rel="external nofollow">ESlint</a> ليعمل مع الواجهة الخلفية. سنستخدمه الآن مع الواجهة الأمامية.
</p>

<p>
	يثبت البرنامج Create-react-app المدقق ESlint تلقائيًا في المشروع، وكل ما يبقى علينا هو كتابة تعليمات التهيئة المطلوبة داخل الملف eslintrc.js.
</p>

<p>
	<strong>ملاحظة</strong>: لا تنفذ الأمر <code>eslint --init</code>. سيثبت هذا الأمر آخر نسخة من ESlint والتي لن تتوافق مع ملف التهيئة الذي ينشئه create<em>react</em>app.
</p>

<p>
	سنبدأ تاليًا باختبار الواجهة الأمامية. ولكي نتجنب أخطاء التدقيق غير المرغوبة أو التي لا تتعلق بشيفرتنا، سنثبت الحزمة <a data-ss1613492867="1" href="https://www.npmjs.com/package/eslint-plugin-jest" rel="external nofollow">eslint-jest-plugin</a>:
</p>

<pre class="ipsCode">
npm add --save-dev eslint-plugin-jest
</pre>

<p>
	لننشئ الملف eslintrc.js الذي يحتوي الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9058_60" style="">
<span class="pln">module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="str">"env"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="str">"browser"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"es6"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"jest/globals"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> 
  </span><span class="pun">},</span><span class="pln">
  </span><span class="str">"extends"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> 
      </span><span class="str">"eslint:recommended"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"plugin:react/recommended"</span><span class="pln">
  </span><span class="pun">],</span><span class="pln">
  </span><span class="str">"parserOptions"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="str">"ecmaFeatures"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          </span><span class="str">"jsx"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      </span><span class="str">"ecmaVersion"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2018</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"sourceType"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"module"</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="str">"plugins"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
      </span><span class="str">"react"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"jest"</span><span class="pln">
  </span><span class="pun">],</span><span class="pln">
  </span><span class="str">"rules"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="str">"indent"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
          </span><span class="str">"error"</span><span class="pun">,</span><span class="pln">
          </span><span class="lit">2</span><span class="pln">  
      </span><span class="pun">],</span><span class="pln">
      </span><span class="str">"linebreak-style"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
          </span><span class="str">"error"</span><span class="pun">,</span><span class="pln">
          </span><span class="str">"unix"</span><span class="pln">
      </span><span class="pun">],</span><span class="pln">
      </span><span class="str">"quotes"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
          </span><span class="str">"error"</span><span class="pun">,</span><span class="pln">
          </span><span class="str">"single"</span><span class="pln">
      </span><span class="pun">],</span><span class="pln">
      </span><span class="str">"semi"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
          </span><span class="str">"error"</span><span class="pun">,</span><span class="pln">
          </span><span class="str">"never"</span><span class="pln">
      </span><span class="pun">],</span><span class="pln">
      </span><span class="str">"eqeqeq"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"error"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"no-trailing-spaces"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"error"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"object-curly-spacing"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
          </span><span class="str">"error"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"always"</span><span class="pln">
      </span><span class="pun">],</span><span class="pln">
      </span><span class="str">"arrow-spacing"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
          </span><span class="str">"error"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="str">"before"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln"> </span><span class="str">"after"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">],</span><span class="pln">
      </span><span class="str">"no-console"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"react/prop-types"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="str">"settings"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"react"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="str">"version"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"detect"</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	<strong>ملاحظة</strong>: إن كنت تستخدم ESlint كإضافة مع Visual Studio Code، قد تحتاج إلى إعدادات إضافية لفضاء العمل حتى يعمل. وإن كنت ترى الرسالة:
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p>
		"Failed to load plugin react: Cannot find module 'eslint-plugin-react"
	</p>
</blockquote>

<p>
	فهذا دليل على أنك تحتاج إلى مزيد من تعليمات التهيئة.
</p>

<p>
	قد يؤدي إضافة الأمر <code>"eslint.workingDirectories": [{ "mode": "auto" }]</code> إلى الملف setting.json في فضاء العمل إلى حل المشكلة. يمكنك الاطلاع على المزيد حول الموضوع <a data-ss1613492867="1" href="https://github.com/microsoft/vscode-eslint/issues/880#issuecomment-578052807" rel="external nofollow">عبر الانترنت</a>.
</p>

<p>
	لننشئ ملف تجاهل قواعد eslint ذو اللاحقة <a data-ss1613492867="1" href="https://eslint.org/docs/user-guide/configuring#ignoring-files-and-directorie" rel="external nofollow">eslintignore.</a> بحيث يحتوي الشيفرة التالية:
</p>

<pre class="ipsCode">
node_modules
build
</pre>

<p>
	وهكذا لن تخضع المجلدات "build" و"node_modules" لعملية التدقيق.
</p>

<p>
	لننشئ أيضًا سكربت npm لتشغيل المدقق:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9058_62" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"scripts"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"start"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"react-scripts start"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"build"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"react-scripts build"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"test"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"react-scripts test"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"eject"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"react-scripts eject"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"server"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"json-server -p3001 db.json"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"eslint"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"eslint ."</span><span class="pln">  </span><span class="pun">},</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيسبب المكوِّن تحذيرًا مزعجًا: "لا يحمل تعريف المكوِّن اسمًا لعرضه" (Component definition is missing display name).
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-ss1613492867="1" href="https://academy.hsoub.com/uploads/monthly_2021_02/componnent_warn_display_name_10.png.1cf501acc21106d50789a22b37a2d3fe.png" data-fileid="57807" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="57807" data-unique="syrzsei01" src="https://academy.hsoub.com/uploads/monthly_2021_02/componnent_warn_display_name_10.png.1cf501acc21106d50789a22b37a2d3fe.png" alt="componnent_warn_display_name_10.png"></a>
</p>

<p>
	وستكشف أداة تطوير React أيضًا أن المكوِّن لا يحمل اسمًا:
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="57814" data-unique="2886kjpra" src="https://academy.hsoub.com/uploads/monthly_2021_02/react_comp_no_name_11.png.2d6af5cbbc9103882701eaf6f3006eb6.png" alt="react_comp_no_name_11.png"></p>

<p>
	لكن إصلاح ذلك أمر يسير.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9058_64" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> useState</span><span class="pun">,</span><span class="pln"> useImperativeHandle </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">PropTypes</span><span class="pln"> from </span><span class="str">'prop-types'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Togglable</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">React</span><span class="pun">.</span><span class="pln">forwardRef</span><span class="pun">((</span><span class="pln">props</span><span class="pun">,</span><span class="pln"> ref</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

</span><span class="typ">Togglable</span><span class="pun">.</span><span class="pln">displayName </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Togglable'</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">Togglable</span></pre>

<p>
	يمكنك إيجاد شيفرة التطبيق بالكامل ضمن الفرع part5-7 في الستودع الخاص بالتطبيق على <a data-ss1613492867="1" href="https://github.com/fullstack-hy2020/part2-notes/tree/part5-7" rel="external nofollow">GitHub</a>.
</p>

<h2>
	التمرينان 5.11 - 5.12
</h2>

<h3>
	5.11 واجهة أمامية لقائمة المدونات: الخطوة 11
</h3>

<p>
	عرّف خاصة نمطية propTypes لأحد مكوِّنات التطبيق.
</p>

<h3>
	5.12 واجهة أمامية لقائمة المدونات: الخطوة 12
</h3>

<p>
	أضف المدقق ESlint إلى التطبيق. أضف ما ترغب من قواعد التهيئة إلى المدقق، وأصلح كل الأخطاء الناتجة عنه.
</p>

<p>
	يثبت البرنامج create-react-app المدقق ESlint تلقائيًا في المشروع، وكل ما يبقى عليك هو كتابة تعليمات التهيئة المطلوبة داخل الملف eslintrc.js.
</p>

<p>
	<strong>ملاحظة</strong>: لا تنفذ الأمر <code>eslint --init</code>. سيثبت هذا الأمر آخر نسخة من ESlint والتي لن تتوافق مع ملف التهيئة الذي ينشئه create-react-app.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a data-ss1613492867="1" href="https://fullstackopen.com/en/part5/props_children_and_proptypes" rel="external nofollow">props.children, proptypes</a> من سلسلة <a data-ss1613492867="1" href="https://fullstackopen.com/en/" rel="external nofollow">Deep Dive Into Modern Web Development</a>
</p>
]]></description><guid isPermaLink="false">1137</guid><pubDate>Tue, 16 Feb 2021 16:35:48 +0000</pubDate></item><item><title>&#x62A;&#x646;&#x641;&#x64A;&#x630; &#x639;&#x645;&#x644;&#x64A;&#x629; &#x62A;&#x633;&#x62C;&#x64A;&#x644; &#x627;&#x644;&#x62F;&#x62E;&#x648;&#x644; &#x641;&#x64A; &#x627;&#x644;&#x648;&#x627;&#x62C;&#x647;&#x629; &#x627;&#x644;&#x623;&#x645;&#x627;&#x645;&#x64A;&#x629; &#x641;&#x64A; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; React</title><link>https://academy.hsoub.com/programming/javascript/react/%D8%AA%D9%86%D9%81%D9%8A%D8%B0-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D8%B3%D8%AC%D9%8A%D9%84-%D8%A7%D9%84%D8%AF%D8%AE%D9%88%D9%84-%D9%81%D9%8A-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%A3%D9%85%D8%A7%D9%85%D9%8A%D8%A9-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-react-r1136/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_02/602beff6bdf37_----.png.d12f483744bef0ec26e425ad641c44aa.png" /></p>

<p>
	لقد انصب اهتمامنا في القسمين السابقين على الواجهة الخلفية بشكل رئيسي، فلم تُدعم الواجهة الأمامية بوظائف إدارة المستخدمين التي أضفناها إلى الواجهة الخلفية في القسم 4 السابق (الذي يبدأ من درس <a data-ss1613492206="1" data-ss1613492673="1" href="https://academy.hsoub.com/programming/javascript/nodejs/express/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-nodejs-%D9%88express-r1099/" rel="">مدخل إلى Node.js وExpress</a>).
</p>

<p>
	تُظهر الواجهة الأمامية حاليًا الملاحظات الموجودة، وتعطي المستخدم امكانية تعديل أهمية الملاحظة. لم تعد هناك إمكانية لإضافة ملاحظات جديدة بعد التعديلات التي أجريناها على الواجهة الخلفية في القسم 4. حيث تتوقع الواجهة الخلفية إرفاق شهادة لتأكيد هوية المستخدم مع الملاحظة الجديدة.
</p>

<p>
	سنضيف جزءًا من وظيفة إدارة المستخدمين إلى الواجهة الأمامية. سنبدأ بواجهة تسجيل الدخول، وسنفترض عدم إمكانية إضافة مستخدمين جدد من الواجهة الأمامية.
</p>

<p>
	أُضيف نموذج تسجيل الدخول إلى أعلى الصفحة، وكذلك نُقل نموذج إضافة ملاحظة جديدة إلى أعلى قائمة الملاحظات
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="57798" data-ss1613492206="1" data-ss1613492673="1" href="https://academy.hsoub.com/uploads/monthly_2021_02/login_form_01.png.e35bca96bb3a4a1e64697ef0fc1a6eab.png" rel=""><img alt="login_form_01.png" class="ipsImage ipsImage_thumbnailed" data-fileid="57798" data-unique="ldt3xz7as" src="https://academy.hsoub.com/uploads/monthly_2021_02/login_form_01.png.e35bca96bb3a4a1e64697ef0fc1a6eab.png"></a>
</p>

<p>
	سيبدو شكل المكوّن App كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1884_8" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">notes</span><span class="pun">,</span><span class="pln"> setNotes</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">([])</span><span class="pln"> 
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">newNote</span><span class="pun">,</span><span class="pln"> setNewNote</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">showAll</span><span class="pun">,</span><span class="pln"> setShowAll</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">errorMessage</span><span class="pun">,</span><span class="pln"> setErrorMessage</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="kwd">null</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">username</span><span class="pun">,</span><span class="pln"> setUsername</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln">   
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">password</span><span class="pun">,</span><span class="pln"> setPassword</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln"> 
  useEffect</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    noteService
      </span><span class="pun">.</span><span class="pln">getAll</span><span class="pun">().</span><span class="pln">then</span><span class="pun">(</span><span class="pln">initialNotes </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        setNotes</span><span class="pun">(</span><span class="pln">initialNotes</span><span class="pun">)</span><span class="pln">
      </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">},</span><span class="pln"> </span><span class="pun">[])</span><span class="pln">

  </span><span class="com">// ...</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> handleLogin </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">    
event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">    
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'logging in with'</span><span class="pun">,</span><span class="pln"> username</span><span class="pun">,</span><span class="pln"> password</span><span class="pun">)</span><span class="pln">  
</span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Notes</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">

      </span><span class="pun">&lt;</span><span class="typ">Notification</span><span class="pln"> message</span><span class="pun">={</span><span class="pln">errorMessage</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">

      </span><span class="pun">&lt;</span><span class="pln">form onSubmit</span><span class="pun">={</span><span class="pln">handleLogin</span><span class="pun">}&gt;</span><span class="pln">        
          </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">          
          username            
</span><span class="pun">&lt;</span><span class="pln">input            
type</span><span class="pun">=</span><span class="str">"text"</span><span class="pln">            
value</span><span class="pun">={</span><span class="pln">username</span><span class="pun">}</span><span class="pln">            
name</span><span class="pun">=</span><span class="str">"Username"</span><span class="pln">            
onChange</span><span class="pun">={({</span><span class="pln"> target </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setUsername</span><span class="pun">(</span><span class="pln">target</span><span class="pun">.</span><span class="pln">value</span><span class="pun">)}</span><span class="pln">          
</span><span class="pun">/&gt;</span><span class="pln">        
</span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">        
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    password
</span><span class="pun">&lt;</span><span class="pln">input
type</span><span class="pun">=</span><span class="str">"password"</span><span class="pln">            
value</span><span class="pun">={</span><span class="pln">password</span><span class="pun">}</span><span class="pln">
name</span><span class="pun">=</span><span class="str">"Password"</span><span class="pln">            
onChange</span><span class="pun">={({</span><span class="pln"> target </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setPassword</span><span class="pun">(</span><span class="pln">target</span><span class="pun">.</span><span class="pln">value</span><span class="pun">)}</span><span class="pln">          
</span><span class="pun">/&gt;</span><span class="pln">        
</span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">        
    </span><span class="pun">&lt;</span><span class="pln">button type</span><span class="pun">=</span><span class="str">"submit"</span><span class="pun">&gt;</span><span class="pln">login</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">      
</span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="com">// ...</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">App</span></pre>

<p>
	يمكن أن تجد شيفرة التطبيق بوضعها الحالي في الفرع part5-1 على <a data-ss1613492206="1" data-ss1613492673="1" href="https://github.com/fullstack-hy2020/part2-notes/tree/part5-1" rel="external nofollow">GitHub</a>
</p>

<p>
	نتعامل مع نموذج تسجيل الدخول بالطريقة ذاتها التي تعاملنا فيها مع النماذج في <a data-ss1613492206="1" data-ss1613492673="1" href="https://fullstackopen.com/en/part2/forms" rel="external nofollow">القسم 2</a>. تحتوي حالة التطبيق على حقول لكلمة السر واسم المستخدم لتخزين البيانات الموجودة في نموذج تسجيل الدخول. ولتلك الحقول معالجات أحداث تُزامن التغيرات في الحقول مع حالة المكون App. تعتمد معالجات الأحداث مبدأً بسيطًا، حيث يمرر كائن لها كوسيط ثم تفكك الحقل عن الكائن وتخزن قيمته في حالة التطبيق.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1884_12" style="">
<span class="pun">({</span><span class="pln"> target </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setUsername</span><span class="pun">(</span><span class="pln">target</span><span class="pun">.</span><span class="pln">value</span><span class="pun">)</span></pre>

<p>
	لم نضف التابع <code>handlelogin</code> المسؤول عن التعامل مع البيانات في النموذج بعد.
</p>

<p>
	تجري عملية تسجيل الدخول بإرسال طلب HTTP POST إلى عنوان الموقع api/login/. لهذا سنضع الشيفرة المسؤولة عن هذا الطلب في وحدة مستقلة خاصة باسم login.js ضمن المجلد services.
</p>

<p>
	سنستخدم async/await بدلًا من الوعود للتعامل مع طلبات HTTP.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1884_14" style="">
<span class="kwd">import</span><span class="pln"> axios from </span><span class="str">'axios'</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> baseUrl </span><span class="pun">=</span><span class="pln"> </span><span class="str">'/api/login'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> login </span><span class="pun">=</span><span class="pln"> async credentials </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> response </span><span class="pun">=</span><span class="pln"> await axios</span><span class="pun">.</span><span class="pln">post</span><span class="pun">(</span><span class="pln">baseUrl</span><span class="pun">,</span><span class="pln"> credentials</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> login </span><span class="pun">}</span></pre>

<p>
	يمكن إضافة التابع المسؤول عن تسجيل الدخول كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1884_16" style="">
<span class="kwd">import</span><span class="pln"> loginService from </span><span class="str">'./services/login'</span><span class="pln"> 

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">username</span><span class="pun">,</span><span class="pln"> setUsername</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln"> 
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">password</span><span class="pun">,</span><span class="pln"> setPassword</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln"> 
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">user</span><span class="pun">,</span><span class="pln"> setUser</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="kwd">null</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> handleLogin </span><span class="pun">=</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">

    </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">const</span><span class="pln"> user </span><span class="pun">=</span><span class="pln"> await loginService</span><span class="pun">.</span><span class="pln">login</span><span class="pun">({</span><span class="pln">
            username</span><span class="pun">,</span><span class="pln"> password</span><span class="pun">,</span><span class="pln">
        </span><span class="pun">})</span><span class="pln">
        setUser</span><span class="pun">(</span><span class="pln">user</span><span class="pun">)</span><span class="pln">
        setUsername</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln">
        setPassword</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
      </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">exception</span><span class="pun">)</span><span class="pln"> 
      </span><span class="pun">{</span><span class="pln">      
          setErrorMessage</span><span class="pun">(</span><span class="str">'Wrong credentials'</span><span class="pun">)</span><span class="pln">      
          setTimeout</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">        
              setErrorMessage</span><span class="pun">(</span><span class="kwd">null</span><span class="pun">)</span><span class="pln">      
          </span><span class="pun">},</span><span class="pln"> </span><span class="lit">5000</span><span class="pun">)</span><span class="pln">    
      </span><span class="pun">}</span><span class="pln">  
  </span><span class="pun">}</span><span class="pln">

  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	إن نجح تسجيل الدخول، ستُفرَّغ حقول نموذج التسجيل، وتُحفظ استجابة الخادم (بما فيها الشهادة والتفاصيل) في الحقل <code>user</code> من حالة التطبيق. أما إن فشل تسجيل الدخول، أو نتج خطأ عن تنفيذ التابع <code>loginService.login</code>، سيتلقى المستخدم إشعارًا بذلك، ولن يتلقى المستخدم إشعارًا بنجاح العملية.
</p>

<p>
	لنعدّل التطبيق بحيث يظهر نموذج تسجيل الدخول فقط إذا لم يكن قد سجل المستخدم دخوله بعد. أي عندما تكون قيمة الحقل <code>user</code> لاشيء (Null). وكذلك لن يظهر نموذج إضافة ملاحظة جديدة إن لم يسجل المستخدم دخوله، أي يجب أن يحتوي الحقل <code>user</code> تفاصيل المستخدم.
</p>

<p>
	سنضيف دالتين مساعدتين إلى المكوِّن App لتوليد النموذجين:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1884_18" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> loginForm </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">form onSubmit</span><span class="pun">={</span><span class="pln">handleLogin</span><span class="pun">}&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        username
          </span><span class="pun">&lt;</span><span class="pln">input
          type</span><span class="pun">=</span><span class="str">"text"</span><span class="pln">
          value</span><span class="pun">={</span><span class="pln">username</span><span class="pun">}</span><span class="pln">
          name</span><span class="pun">=</span><span class="str">"Username"</span><span class="pln">
          onChange</span><span class="pun">={({</span><span class="pln"> target </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setUsername</span><span class="pun">(</span><span class="pln">target</span><span class="pun">.</span><span class="pln">value</span><span class="pun">)}</span><span class="pln">
        </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        password
          </span><span class="pun">&lt;</span><span class="pln">input
          type</span><span class="pun">=</span><span class="str">"password"</span><span class="pln">
          value</span><span class="pun">={</span><span class="pln">password</span><span class="pun">}</span><span class="pln">
          name</span><span class="pun">=</span><span class="str">"Password"</span><span class="pln">
          onChange</span><span class="pun">={({</span><span class="pln"> target </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setPassword</span><span class="pun">(</span><span class="pln">target</span><span class="pun">.</span><span class="pln">value</span><span class="pun">)}</span><span class="pln">
        </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button type</span><span class="pun">=</span><span class="str">"submit"</span><span class="pun">&gt;</span><span class="pln">login</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">      
  </span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> noteForm </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">form onSubmit</span><span class="pun">={</span><span class="pln">addNote</span><span class="pun">}&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">input
        value</span><span class="pun">={</span><span class="pln">newNote</span><span class="pun">}</span><span class="pln">
        onChange</span><span class="pun">={</span><span class="pln">handleNoteChange</span><span class="pun">}</span><span class="pln">
      </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button type</span><span class="pun">=</span><span class="str">"submit"</span><span class="pun">&gt;</span><span class="pln">save</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">  
  </span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="com">// ...</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ثم سنصيّرهما شرطيًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1884_20" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> loginForm </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="com">// ...</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> noteForm </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="com">// ...</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Notes</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">

      </span><span class="pun">&lt;</span><span class="typ">Notification</span><span class="pln"> message</span><span class="pun">={</span><span class="pln">errorMessage</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">

      </span><span class="pun">{</span><span class="pln">user </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">null</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> loginForm</span><span class="pun">()}</span><span class="pln">      
      </span><span class="pun">{</span><span class="pln">user </span><span class="pun">!==</span><span class="pln"> </span><span class="kwd">null</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> noteForm</span><span class="pun">()}</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setShowAll</span><span class="pun">(!</span><span class="pln">showAll</span><span class="pun">)}&gt;</span><span class="pln">
          show </span><span class="pun">{</span><span class="pln">showAll </span><span class="pun">?</span><span class="pln"> </span><span class="str">'important'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">'all'</span><span class="pun">}</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">notesToShow</span><span class="pun">.</span><span class="pln">map</span><span class="pun">((</span><span class="pln">note</span><span class="pun">,</span><span class="pln"> i</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> 
          </span><span class="pun">&lt;</span><span class="typ">Note</span><span class="pln">
            key</span><span class="pun">={</span><span class="pln">i</span><span class="pun">}</span><span class="pln">
            note</span><span class="pun">={</span><span class="pln">note</span><span class="pun">}</span><span class="pln"> 
            toggleImportance</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> toggleImportanceOf</span><span class="pun">(</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">)}</span><span class="pln">
          </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">)}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">

      </span><span class="pun">&lt;</span><span class="typ">Footer</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيبدو شكلها غريبًا قليلًا، إلا أنها <a data-ss1613492206="1" data-ss1613492673="1" href="https://reactjs.org/docs/conditional-rendering.html#inline-if-with-logical--operator" rel="external nofollow">حيلة في React</a> تُستخدم لتصيير النماذج شرطيًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1884_22" style="">
<span class="pun">{</span><span class="pln">
  user </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">null</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> loginForm</span><span class="pun">()</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	فإن كانت نتيجة تنفيذ العبارة الأولى (خطأ)، أو كانت قيمتها <a data-ss1613492206="1" data-ss1613492673="1" href="https://developer.mozilla.org/en-US/docs/Glossary/Falsy" rel="external nofollow">خاطئة</a>، لن تُنفَّذ العبارة الثانية (العبارة التي تولد النموذج).
</p>

<p>
	كما يمكننا تنفيذ ذلك مباشرة باستخدام <a data-ss1613492206="1" data-ss1613492673="1" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator" rel="external nofollow">العامل الشرطي</a>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1884_24" style="">
<span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Notes</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">

    </span><span class="pun">&lt;</span><span class="typ">Notification</span><span class="pln"> message</span><span class="pun">={</span><span class="pln">errorMessage</span><span class="pun">}/&gt;</span><span class="pln">

    </span><span class="pun">{</span><span class="pln">user </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">null</span><span class="pln"> </span><span class="pun">?</span><span class="pln">
      loginForm</span><span class="pun">()</span><span class="pln"> </span><span class="pun">:</span><span class="pln">
      noteForm</span><span class="pun">()</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="pun">&lt;</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="typ">Notes</span><span class="pun">&lt;/</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">

    </span><span class="com">// ...</span><span class="pln">

  </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">)</span></pre>

<p>
	إن كانت نتيجة الموازنة <code>user === null</code> <a data-ss1613492206="1" data-ss1613492673="1" href="https://developer.mozilla.org/en-US/docs/Glossary/Truthy" rel="external nofollow">صحيحة</a>، سيُنفَّذ الأمر <code>()loginForm</code>، وإلا سيُنفَّذ الأمر <code>()noteForm</code>.
</p>

<p>
	سنجري تعديلًا أخيرًا يظهر فيه اسم المستخدم على الشاشة عندما يسجل دخوله:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1884_26" style="">
<span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Notes</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">

    </span><span class="pun">&lt;</span><span class="typ">Notification</span><span class="pln"> message</span><span class="pun">={</span><span class="pln">errorMessage</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">

    </span><span class="pun">{</span><span class="pln">user </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">null</span><span class="pln"> </span><span class="pun">?</span><span class="pln">
      loginForm</span><span class="pun">()</span><span class="pln"> </span><span class="pun">:</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;{</span><span class="pln">user</span><span class="pun">.</span><span class="pln">name</span><span class="pun">}</span><span class="pln"> logged</span><span class="pun">-</span><span class="pln">in</span><span class="pun">&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">noteForm</span><span class="pun">()}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="pun">&lt;</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="typ">Notes</span><span class="pun">&lt;/</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">

    </span><span class="com">// ...</span><span class="pln">

  </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">)</span></pre>

<p>
	لم نقدم الحل المثالي بعد، لكننا سنكتفي بما فعلناه حاليًا.
</p>

<p>
	لقد أصبح المكون الرئيسي ضخمًا، وهذه علامة على ضرورة إعادة كتابة شيفرة النماذج ضمن مكوناتها الخاصة. سنترك هذا الأمر لننفذه لاحقًا ضمن التمارين الاختيارية.
</p>

<p>
	ستجد شيفرة التطبيق ضمن الفرع part5-2 على <a data-ss1613492206="1" data-ss1613492673="1" href="https://github.com/fullstack-hy2020/part2-notes/tree/part5-2" rel="external nofollow">GitHub</a>.
</p>

<h2>
	إنشاء ملاحظات جديدة
</h2>

<p>
	تُحفظ الشهادة التي تعاد من الخادم بعد نجاح تسجيل الدخول ضمن الحقل <code>user.token</code> في حالة التطبيق.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1884_28" style="">
<span class="kwd">const</span><span class="pln"> handleLogin </span><span class="pun">=</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">
  </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> user </span><span class="pun">=</span><span class="pln"> await loginService</span><span class="pun">.</span><span class="pln">login</span><span class="pun">({</span><span class="pln">
      username</span><span class="pun">,</span><span class="pln"> password</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">

    setUser</span><span class="pun">(</span><span class="pln">user</span><span class="pun">)</span><span class="pln">
    setUsername</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln">
    setPassword</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> 
    </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">exception</span><span class="pun">)</span><span class="pln"> 
    </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ...</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لنصلح عملية إنشاء ملاحظة جديدة لتعمل مع الواجهة الخلفية، بإضافة شهادة المستخدم (بعد أن يسجل دخوله) إلى ترويسة تفويض طلب HTTP.
</p>

<p>
	ستصبح الوحدة <code>noteService</code> على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1884_30" style="">
<span class="kwd">import</span><span class="pln"> axios from </span><span class="str">'axios'</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> baseUrl </span><span class="pun">=</span><span class="pln"> </span><span class="str">'/api/notes'</span><span class="pln">

let token </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> setToken </span><span class="pun">=</span><span class="pln"> newToken </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  
    token </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">bearer $</span><span class="pun">{</span><span class="pln">newToken</span><span class="pun">}</span><span class="pln">
</span><span class="pun">`}</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> getAll </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> request </span><span class="pun">=</span><span class="pln"> axios</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="pln">baseUrl</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> request</span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> create </span><span class="pun">=</span><span class="pln"> async newObject </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> config </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">    
      headers</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Authorization</span><span class="pun">:</span><span class="pln"> token </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> response </span><span class="pun">=</span><span class="pln"> await axios</span><span class="pun">.</span><span class="pln">post</span><span class="pun">(</span><span class="pln">baseUrl</span><span class="pun">,</span><span class="pln"> newObject</span><span class="pun">,</span><span class="pln"> config</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data   
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> update </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">id</span><span class="pun">,</span><span class="pln"> newObject</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> request </span><span class="pun">=</span><span class="pln"> axios</span><span class="pun">.</span><span class="pln">put</span><span class="pun">(`</span><span class="pln">$</span><span class="pun">{</span><span class="pln"> baseUrl </span><span class="pun">}</span><span class="pln"> </span><span class="pun">/</span><span class="pln">$</span><span class="pun">{</span><span class="pln">id</span><span class="pun">}`,</span><span class="pln"> newObject</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> request</span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> getAll</span><span class="pun">,</span><span class="pln"> create</span><span class="pun">,</span><span class="pln"> update</span><span class="pun">,</span><span class="pln"> setToken </span><span class="pun">}</span></pre>

<p>
	تحتوي الوحدة على المتغير الخاص <code>token</code>، الذي يمكن تغيير قيمته باستخدام الدالة <code>setToken</code> التي يصدّرها النموذج. تضع الدالة الشهادة في ترويسة التفويض باستعمال async/await. ولاحظ أن هذه الدالة ستُمرَّر كمعامل ثالث إلى التابع <code>post</code> العائد للمكتبة axios. ينبغي تغيير معالج الحدث المسؤول عن تسجيل الدخول ليستدعي التابع <code>(noteService.setToken(user.token</code> عند نجاح تسجيل الدخول:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1884_32" style="">
<span class="kwd">const</span><span class="pln"> handleLogin </span><span class="pun">=</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">
  </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> user </span><span class="pun">=</span><span class="pln"> await loginService</span><span class="pun">.</span><span class="pln">login</span><span class="pun">({</span><span class="pln">
      username</span><span class="pun">,</span><span class="pln"> password</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">

    noteService</span><span class="pun">.</span><span class="pln">setToken</span><span class="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">token</span><span class="pun">)</span><span class="pln">    
    setUser</span><span class="pun">(</span><span class="pln">user</span><span class="pun">)</span><span class="pln">
    setUsername</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln">
    setPassword</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">exception</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ...</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وهكذا سنتمكن من إضافة ملاحظات جديدة.
</p>

<h2>
	تخزين الشهادة في ذاكرة المتصفح
</h2>

<p>
	لا تزال هناك ثغرة في التطبيق. فعندما يُعاد تصيير الصفحة ستختفي معلومات المستخدم. ستبطئ هذه الثغرة عملية التطوير. إذا علينا مثلًا أن نسجل الدخول في كل مرة نحاول فيها إنشاء ملاحظة جديدة.
</p>

<p>
	تُحل هذه المشكلة بسهولة إذا ما خزّنا تفاصيل عملية تسجيل الدخول ضمن <a data-ss1613492206="1" data-ss1613492673="1" href="https://developer.mozilla.org/en-US/docs/Web/API/Storage" rel="external nofollow">الذاكرة المحلية للمتصفح</a>، وهي قاعدة بيانات في المتصفح تخزن البيانات بطريقة <a data-ss1613492206="1" data-ss1613492673="1" href="https://en.wikipedia.org/wiki/Key-value_database" rel="external nofollow">مفتاح-قيمة</a>، واستخدامها سهل للغاية. حيث ترتبط كل قيمة في هذه الذاكرة بمفتاح وتحفظ في قاعدة بيانات المتصفح باستخدام التابع <a data-ss1613492206="1" data-ss1613492673="1" href="https://developer.mozilla.org/en-US/docs/Web/API/Storage/setItem" rel="external nofollow">setItem</a>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1884_34" style="">
<span class="pln">window</span><span class="pun">.</span><span class="pln">localStorage</span><span class="pun">.</span><span class="pln">setItem</span><span class="pun">(</span><span class="str">'name'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'juha tauriainen'</span><span class="pun">)</span></pre>

<p>
	حيث يخزّن التابع في الشيفرة السابقة مثلًا، المعامل الثاني كقيمة للمفتاح name.
</p>

<p>
	يمكن الحصول على قيمة المفتاح باستخدام التابع <a data-ss1613492206="1" data-ss1613492673="1" href="https://developer.mozilla.org/en-US/docs/Web/API/Storage/getItem" rel="external nofollow">getItem</a>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1884_38" style="">
<span class="pln">window</span><span class="pun">.</span><span class="pln">localStorage</span><span class="pun">.</span><span class="pln">getItem</span><span class="pun">(</span><span class="str">'name'</span><span class="pun">)</span></pre>

<p>
	كما يمكن حذفه باستخدام التابع <a data-ss1613492206="1" data-ss1613492673="1" href="https://developer.mozilla.org/en-US/docs/Web/API/Storage/removeItem" rel="external nofollow">removeItem</a>.
</p>

<p>
	ستبقى القيم في الذاكرة المحلية حتى لو أعدنا تصيير الصفحة، وهذه ذاكرة خاصة <a data-ss1613492206="1" data-ss1613492673="1" href="https://developer.mozilla.org/en-US/docs/Glossary/Origin" rel="external nofollow">بالمَنشأ</a>، أي أن كل تطبيق سيحتفظ بذاكرته الخاصة. سنوسع التطبيق لكي تُحفظ تفاصيل تسجيل الدخول في الذاكرة المحلية.
</p>

<p>
	إن القيم التي تحفظ في الذاكرة من النوع <a data-ss1613492206="1" data-ss1613492673="1" href="https://developer.mozilla.org/en-US/docs/Web/API/DOMString" rel="external nofollow">DOMstrings</a>، لذلك لن نتمكن من حفظ كائن JavaScript كما هو. إذًا، يجب تحويل الكائن إلى تنسيق JSON أولًا باستخدام التابع <code>JSON.stringify</code>. وبالعكس لابد من تحويل المعلومات التي تُقرأ من الذاكرة إلى كائن JavaScript باستخدام التابع <code>JSON.parse</code>.
</p>

<p>
	ستصبح شيفرة تسجيل الدخول كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1884_40" style="">
<span class="pln">  </span><span class="kwd">const</span><span class="pln"> handleLogin </span><span class="pun">=</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">const</span><span class="pln"> user </span><span class="pun">=</span><span class="pln"> await loginService</span><span class="pun">.</span><span class="pln">login</span><span class="pun">({</span><span class="pln">
        username</span><span class="pun">,</span><span class="pln"> password</span><span class="pun">,</span><span class="pln">
      </span><span class="pun">})</span><span class="pln">

      window</span><span class="pun">.</span><span class="pln">localStorage</span><span class="pun">.</span><span class="pln">setItem</span><span class="pun">(</span><span class="pln">        
          </span><span class="str">'loggedNoteappUser'</span><span class="pun">,</span><span class="pln"> JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">(</span><span class="pln">user</span><span class="pun">)</span><span class="pln">
      </span><span class="pun">)</span><span class="pln">       
      noteService</span><span class="pun">.</span><span class="pln">setToken</span><span class="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">token</span><span class="pun">)</span><span class="pln">
      setUser</span><span class="pun">(</span><span class="pln">user</span><span class="pun">)</span><span class="pln">
      setUsername</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln">
      setPassword</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">exception</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="com">// ...</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span></pre>

<p>
	وهكذا سنحتفظ ببيانات تسجيل الدخول في الذاكرة المحلية والتي يمكن عرضها على الطرفية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="57797" data-ss1613492206="1" data-ss1613492673="1" href="https://academy.hsoub.com/uploads/monthly_2021_02/local_storage_values_02.png.d427a3e9d2e1076dffb15fcb7de78e65.png" rel=""><img alt="local_storage_values_02.png" class="ipsImage ipsImage_thumbnailed" data-fileid="57797" data-unique="fe6m61ykx" src="https://academy.hsoub.com/uploads/monthly_2021_02/local_storage_values_02.png.d427a3e9d2e1076dffb15fcb7de78e65.png"></a>
</p>

<p>
	سنتمكن أيضًا من تحري الذاكرة المحلية باستخدام أدوات التطوير. فإن كنت من مستخدمي Chrome، توجه إلى النافذة Application واختر Local storage (ستجد تفاصيل أكثر على <a data-ss1613492206="1" data-ss1613492673="1" href="https://developers.google.com/web/tools/chrome-devtools/storage/localstorage" rel="external nofollow">موقع مطوري Google</a>)، بينما لو كنت من مستخدمي Firefox توجه إلى النافذة Storage واختر Local Storage (ستجد تفاصيل أكثر على <a data-ss1613492206="1" data-ss1613492673="1" href="https://developer.mozilla.org/en-US/docs/Tools/Storage_Inspector" rel="external nofollow">موقع مطوري Mozilla</a>).
</p>

<p>
	بقي علينا أن نعدل التطبيق لكي يتحقق من وجود تفاصيل تسجيل الدخول ضمن الذاكرة المحلية. فإن وُجدت هذه التفاصيل ستُحفظ في حالة التطبيق وفي <code>noteService</code> أيضًا.
</p>

<p>
	أما الطريقة الصحيحة لتنفيذ الأمر هي استخدام <a data-ss1613492206="1" data-ss1613492673="1" href="https://wiki.hsoub.com/React/hooks_effect" rel="external">خطاف التأثير</a>، وهي آلية قدمناها لأول مرة في القسم 2، واستعملناها لإحضار الملاحظات من الخادم.
</p>

<p>
	نستطيع استخدام عدة خطافات تأثير، لذلك سننشئ واحدًا جديدًا ليتعامل مع أول تحميل للصفحة.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1884_42" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">notes</span><span class="pun">,</span><span class="pln"> setNotes</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">([])</span><span class="pln"> 
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">newNote</span><span class="pun">,</span><span class="pln"> setNewNote</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">showAll</span><span class="pun">,</span><span class="pln"> setShowAll</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">errorMessage</span><span class="pun">,</span><span class="pln"> setErrorMessage</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="kwd">null</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">username</span><span class="pun">,</span><span class="pln"> setUsername</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln"> 
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">password</span><span class="pun">,</span><span class="pln"> setPassword</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln"> 
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">user</span><span class="pun">,</span><span class="pln"> setUser</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="kwd">null</span><span class="pun">)</span><span class="pln"> 

  useEffect</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    noteService
      </span><span class="pun">.</span><span class="pln">getAll</span><span class="pun">().</span><span class="pln">then</span><span class="pun">(</span><span class="pln">initialNotes </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        setNotes</span><span class="pun">(</span><span class="pln">initialNotes</span><span class="pun">)</span><span class="pln">
      </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">},</span><span class="pln"> </span><span class="pun">[])</span><span class="pln">

  useEffect</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">    
      </span><span class="kwd">const</span><span class="pln"> loggedUserJSON</span><span class="pun">=</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">localStorage</span><span class="pun">.</span><span class="pln">getItem</span><span class="pun">(</span><span class="str">'loggedNoteappUser'</span><span class="pun">)</span><span class="pln">    
      </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">loggedUserJSON</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">      
          </span><span class="kwd">const</span><span class="pln"> user </span><span class="pun">=</span><span class="pln"> JSON</span><span class="pun">.</span><span class="pln">parse</span><span class="pun">(</span><span class="pln">loggedUserJSON</span><span class="pun">)</span><span class="pln">      
          setUser</span><span class="pun">(</span><span class="pln">user</span><span class="pun">)</span><span class="pln">      
          noteService</span><span class="pun">.</span><span class="pln">setToken</span><span class="pun">(</span><span class="pln">user</span><span class="pun">.</span><span class="pln">token</span><span class="pun">)</span><span class="pln">    
      </span><span class="pun">}</span><span class="pln">  
  </span><span class="pun">},</span><span class="pln"> 
            </span><span class="pun">[])</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يضمن تمرير المصفوفة الفارغة إلى خطاف التأثير أن تنفيذه سيتم فقط عندما يُصير المكون <a data-ss1613492206="1" data-ss1613492673="1" href="https://wiki.hsoub.com/React/hooks_reference#.D8.AA.D9.86.D9.81.D9.8A.D8.B0_.D8.AA.D8.A3.D8.AB.D9.8A.D8.B1_.D8.B4.D8.B1.D8.B7.D9.8A.D9.8B.D9.91.D8.A7" rel="external">للمرة الأولى</a>. وهكذا سيبقى المستخدم في حالة تسجيل دخول دائمة. وهذا ما يجعلنا نفكر بإضافة وظيفة لتسجيل خروج المستخدم ومسح البيانات من الذاكرة المحلية. لكننا نفضل أن نترك ذلك للتمارين.
</p>

<p>
	يمكن تسجيل الخروج باستعمال الطرفية وهذا كافٍ حتى اللحظة. حيث يمكن تسجيل الخروج بتنفيذ الأمر:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1884_45" style="">
<span class="pln">window</span><span class="pun">.</span><span class="pln">localStorage</span><span class="pun">.</span><span class="pln">removeItem</span><span class="pun">(</span><span class="str">'loggedNoteappUser'</span><span class="pun">)</span></pre>

<p>
	أو بالأمر التالي الذي يفرّغ الذاكرة المحليّة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1884_47" style="">
<span class="pln">window</span><span class="pun">.</span><span class="pln">localStorage</span><span class="pun">.</span><span class="pln">clear</span><span class="pun">()</span></pre>

<p>
	يمكنك إيجاد الشيفرة الحالية للتطبيق ضمن الفرع part5-3 على <a data-ss1613492206="1" data-ss1613492673="1" href="https://github.com/fullstack-hy2020/part2-notes/tree/part5-3" rel="external nofollow">GitHub</a>.
</p>

<h2>
	التمارين 5.1 - 5.4
</h2>

<p>
	سنطور في هذه التمارين واجهة أمامية لتطبيق قائمة المدونات. يمكنك الاستفادة من <a data-ss1613492206="1" data-ss1613492673="1" href="https://github.com/fullstack-hy2020/bloglist-frontend" rel="external nofollow">التطبيق المساعد</a> الموجود على GitHub كأساس لحلك. يتوقع التمرين أن تعمل الواجهة الخلفية على المنفذ 3001.
</p>

<p>
	يكفي أن تسلم التمرين بشكله النهائي، كما يمكنك ترك تعليق بعد كل تمرين، لكن ذلك غير ضروري.
</p>

<p>
	تذكرك التمارين القليلة الأولى بكل ما تعلمته حتى الآن عن React. وستحمل أيضًا قدرًا من التحدي، وخاصة إن لم تكن واجهتك الخلفية مكتملة. قد يكون من الأفضل استخدام الواجهة الخلفية لنموذج الحل الذي اعتمدناه في القسم 4.
</p>

<p>
	تذكر كل الطرق التي تعلمناها في تنقيح التطبيقات أثناء كتابتك للشيفرة، وابق عينيك على طرفية التطوير دائمًا.
</p>

<p>
	<strong>تحذير</strong>: إن لاحظت أنك تستخدم await/async مع then، فتأكد أنك ستقع في الأخطاء بنسبة %99. استخدم أحد الأسلوبين وليس كلاهما.
</p>

<h3>
	5.1 الواجهة الأمامية لقائمة المدونات: الخطوة 1
</h3>

<p>
	انسخ التطبيق المساعد من <a data-ss1613492206="1" data-ss1613492673="1" href="https://github.com/fullstack-hy2020/bloglist-frontend" rel="external nofollow">GitHub</a> بتنفيذ الأمر التالي:
</p>

<pre class="ipsCode">
git clone https://github.com/fullstack-hy2020/bloglist-frontend
</pre>

<p>
	أزل ملف تهيئة git من التطبيق الذي نسخته:
</p>

<pre class="ipsCode">
cd bloglist-frontend   // go to cloned repository
rm -rf .git
</pre>

<p>
	يمكنك تشغيل التطبيق بالطريقة الاعتيادية، لكن عليك أولًا تثبيت الاعتماديات:
</p>

<pre class="ipsCode">
npm install
npm start
</pre>

<p>
	أضف وظيفة تسجيل الدخول إلى التطبيق. يجب أن تحفظ تفاصيل تسجيل الدخول الناجح في الحقل <code>user</code> من حالة التطبيق. لن يظهر سوى نموذج تسجيل الدخول إن لم يسجل المستخدم دخوله بعد.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="57803" data-ss1613492206="1" data-ss1613492673="1" href="https://academy.hsoub.com/uploads/monthly_2021_02/user_login_form_03.png.09e428a9b417d49d4daea0b18e1cc0e0.png" rel=""><img alt="user_login_form_03.png" class="ipsImage ipsImage_thumbnailed" data-fileid="57803" data-unique="69lgacve7" src="https://academy.hsoub.com/uploads/monthly_2021_02/user_login_form_03.png.09e428a9b417d49d4daea0b18e1cc0e0.png"></a>
</p>

<p>
	ستظهر قائمة المدونات بالإضافة إلى اسم المستخدم عندما ينجح في تسجيل دخوله.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="57799" data-ss1613492206="1" data-ss1613492673="1" href="https://academy.hsoub.com/uploads/monthly_2021_02/login_ok_04.png.2d9f10b63c1d6c6c236c8396f62d11b2.png" rel=""><img alt="login_ok_04.png" class="ipsImage ipsImage_thumbnailed" data-fileid="57799" data-unique="ok86665xs" src="https://academy.hsoub.com/uploads/monthly_2021_02/login_ok_04.png.2d9f10b63c1d6c6c236c8396f62d11b2.png"></a>
</p>

<p>
	لا يجب عليك تخزين تفاصيل تسجيل الدخول ضمن الذاكرة المحلية للمتصفح بعد.
</p>

<p>
	<strong>ملاحظة</strong>: يمكن أن تساعدك الشيفرة التالية في تنفيذ التصيير الشرطي للصفحة عند تسجيل الدخول:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1884_49" style="">
<span class="pln">  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">user </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="typ">Log</span><span class="pln"> in to application</span><span class="pun">&lt;/</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="com">//...</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">blogs</span><span class="pun">&lt;/</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">blogs</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">blog </span><span class="pun">=&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">Blog</span><span class="pln"> key</span><span class="pun">={</span><span class="pln">blog</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}</span><span class="pln"> blog</span><span class="pun">={</span><span class="pln">blog</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">)}</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<h3>
	الواجهة الأمامية لقائمة المدونات: الخطوة 2
</h3>

<p>
	اجعل تسجيل الدخول مستمرًا مستخدمًا الذاكرة المحلية للمتصفح، وأضف طريقة لتسجيل الخروج.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="57802" data-ss1613492206="1" data-ss1613492673="1" href="https://academy.hsoub.com/uploads/monthly_2021_02/perm_login_05.png.921a90d47c726867aee05a54648a2931.png" rel=""><img alt="perm_login_05.png" class="ipsImage ipsImage_thumbnailed" data-fileid="57802" data-unique="7eg8azliv" src="https://academy.hsoub.com/uploads/monthly_2021_02/perm_login_05.png.921a90d47c726867aee05a54648a2931.png"></a>
</p>

<p>
	تأكد من عدم تذكر المتصفح أية تفاصيل عن المستخدم بعد تسجيل الخروج.
</p>

<h3>
	5.3 الواجهة الأمامية لقائمة المدونات: الخطوة 3
</h3>

<p>
	وسع التطبيق بحيث يتمكن المستخدم من إضافة مدونات جديدة.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="57796" data-ss1613492206="1" data-ss1613492673="1" href="https://academy.hsoub.com/uploads/monthly_2021_02/add_new_blog_06.png.1562e29db0c421a6cf84795bd71d6d8a.png" rel=""><img alt="add_new_blog_06.png" class="ipsImage ipsImage_thumbnailed" data-fileid="57796" data-unique="ij96jirs5" src="https://academy.hsoub.com/uploads/monthly_2021_02/add_new_blog_06.png.1562e29db0c421a6cf84795bd71d6d8a.png"></a>
</p>

<h3>
	5.4 الواجهة الأمامية لقائمة المدونات: الخطوة 4 *
</h3>

<p>
	أضف إشعارات إلى التطبيق في أعلى الصفحة، لإبلاغ المستخدم بحالة تسجيل الدخول إن كانت ناجحة أو فاشلة. على سبيل المثال، سيظهر إشعار كهذا عندما نضيف مدونة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="57801" data-ss1613492206="1" data-ss1613492673="1" href="https://academy.hsoub.com/uploads/monthly_2021_02/notification_new_blog_07.png.965bf315ccad9551d0ab2bd96d79b253.png" rel=""><img alt="notification_new_blog_07.png" class="ipsImage ipsImage_thumbnailed" data-fileid="57801" data-unique="qdxgoos4d" src="https://academy.hsoub.com/uploads/monthly_2021_02/notification_new_blog_07.png.965bf315ccad9551d0ab2bd96d79b253.png"></a>
</p>

<p>
	وإشعار كهذا عند فشل تسجيل الدخول:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="57800" data-ss1613492206="1" data-ss1613492673="1" href="https://academy.hsoub.com/uploads/monthly_2021_02/notification_login_failed_08.png.63f7ba7069297ce31e55db6ab5e17a3e.png" rel=""><img alt="notification_login_failed_08.png" class="ipsImage ipsImage_thumbnailed" data-fileid="57800" data-unique="old02r68a" src="https://academy.hsoub.com/uploads/monthly_2021_02/notification_login_failed_08.png.63f7ba7069297ce31e55db6ab5e17a3e.png"></a>
</p>

<p>
	يجب أن يظهر الإشعار لثوان عدة، وليس ضروريًا إضافة الألوان.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a data-ss1613492206="1" data-ss1613492673="1" href="https://fullstackopen.com/en/part5/login_in_frontend" rel="external nofollow">Login in frontend</a> من سلسلة <a data-ss1613492206="1" data-ss1613492673="1" href="https://fullstackopen.com/en/" rel="external nofollow">Deep Dive Into Modern Web Development</a>
</p>
]]></description><guid isPermaLink="false">1136</guid><pubDate>Tue, 16 Feb 2021 16:25:10 +0000</pubDate></item><item><title>&#x625;&#x636;&#x627;&#x641;&#x629; &#x62A;&#x646;&#x633;&#x64A;&#x642;&#x627;&#x62A; &#x625;&#x644;&#x649; &#x62A;&#x637;&#x628;&#x64A;&#x642; React</title><link>https://academy.hsoub.com/programming/javascript/react/%D8%A5%D8%B6%D8%A7%D9%81%D8%A9-%D8%AA%D9%86%D8%B3%D9%8A%D9%82%D8%A7%D8%AA-%D8%A5%D9%84%D9%89-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-react-r1098/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_01/p12-1.jpg.35593f4d818bcd7d63d2c895451b23b4.jpg" /></p>

<p>
	يبدو مظهر تطبيقنا الحالي متواضعًا. لقد طلبنا منك سابقًا في <a href="https://academy.hsoub.com/programming/javascript/react/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r1071/" rel="">التمرين 0.2</a> أن تطلع على <a href="https://academy.hsoub.com/tags/css%2520101/" rel="">دورة تدريبة</a> تتعلق بالتنسيقات المتتالية التي سنستخدمها حاليًا.
</p>

<p>
	لنلقي نظرة على الطريقة التي نضيف فيها تنسيقات لتغيير مظهر التطبيق قبل الانتقال إلى القسم التالي. هناك طرق كثيرة لتنفيذ ذلك، سنلقي عليها نظرة لاحقًا، لكن في البداية سنضيف شيفرة CSS إلى تطبيقنا بالطريقة التقليدية في ملف منفصل واحد دون استخدام معالجة تحضيرية <a href="https://developer.mozilla.org/en-US/docs/Glossary/CSS_preprocessor" rel="external nofollow">CSS preprocessor</a> (وهذا ليس صحيحًا تمامًا كما سنرى).
</p>

<p>
	سننشئ ملفًا باسم index.css ضمن المجلد src ثم نضيفه إلى التطبيق باستخدام تعليمة الإدراج <code>import</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4393_7" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="str">'./index.css'</span></pre>

<p>
	لنضف بعض قواعد التنسيق إلى الملف:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_4393_9" style="">
<span class="pln">h1 </span><span class="pun">{</span><span class="pln">
  color</span><span class="pun">:</span><span class="pln"> green</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تتألف قاعدة التنسيق من المحدد selector والتصريح declaration. يعرّف المحدد العنصر الذي تطبق عليه القاعدة. يطبق المحدد في المثال السابق على عنصر العنوان <code>H1</code> في التطبيق. بينما ينص التصريح على تغيير خاصية اللون إلى الأخضر. يمكن لقاعدة واحدة من قواعد التنسيق أن تغير أي عدد من الخصائص، لنغير إذًا تنسيق الخط ليصبح مائلًا:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_4393_13" style="">
<span class="pln">h1 </span><span class="pun">{</span><span class="pln">
  color</span><span class="pun">:</span><span class="pln"> green</span><span class="pun">;</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">style</span><span class="pun">:</span><span class="pln"> italic</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	هناك العديد من الطرق لاختيار العناصر التي نريد تنسيقها باستخدام <a href="https://wiki.hsoub.com/CSS#.D8.A7.D9.84.D9.85.D9.8F.D8.AD.D8.AF.D9.90.D9.91.D8.AF.D8.A7.D8.AA" rel="external">أنواع مختلفة من محددات التنسيق</a>. فإن أردنا مثًلا أن نغير تنسيق كل ملاحظة من الملاحظات، يمكننا اختيار المحدد li طالما أن الملاحظات ستعرض على شكل عنصر <code>li</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4393_15" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Note</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> note</span><span class="pun">,</span><span class="pln"> toggleImportance </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> label </span><span class="pun">=</span><span class="pln"> note</span><span class="pun">.</span><span class="pln">important 
    </span><span class="pun">?</span><span class="pln"> </span><span class="str">'make not important'</span><span class="pln"> 
    </span><span class="pun">:</span><span class="pln"> </span><span class="str">'make important'</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">content</span><span class="pun">}</span><span class="pln"> 
      </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">toggleImportance</span><span class="pun">}&gt;{</span><span class="pln">label</span><span class="pun">}&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لنضف القاعدة التالية إلى ملف التنسيق:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4393_17" style="">
<span class="pln">li </span><span class="pun">{</span><span class="pln">
  color</span><span class="pun">:</span><span class="pln"> grey</span><span class="pun">;</span><span class="pln">
  padding</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3px</span><span class="pun">;</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">15px</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	إن اختيار قواعد التنسيق لتستهدف العناصر سيسبب بعض المشاكل. فلو احتوى تطبيقنا على عناصر <code>li</code> أخرى ستطبق القاعدة عليها أيضًا. ولتطبيق التنسيق على الملاحظات حصرًا، من الأفضل استخدام محددات الأصناف <a href="https://wiki.hsoub.com/CSS/Class_Selectors" rel="external">class selectors</a>. تعّرف محددات الأصناف في HTML القياسية كقيمة للصفة <code>class</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4393_19" style="">
<span class="tag">&lt;li</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"note"</span><span class="tag">&gt;</span><span class="pln">some text...</span><span class="tag">&lt;/li&gt;</span></pre>

<p>
	بينما في React، علينا أن نستخدم الصفة <a href="https://wiki.hsoub.com/React/dom_elements#className" rel="external">className</a> بدلًا من الصفة class. لنجري الآن بعض التغييرات على المكوِّن <code>Note</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4393_21" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Note</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> note</span><span class="pun">,</span><span class="pln"> toggleImportance </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> label </span><span class="pun">=</span><span class="pln"> note</span><span class="pun">.</span><span class="pln">important 
    </span><span class="pun">?</span><span class="pln"> </span><span class="str">'make not important'</span><span class="pln"> 
    </span><span class="pun">:</span><span class="pln"> </span><span class="str">'make important'</span><span class="pun">;</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">li className</span><span class="pun">=</span><span class="str">'note'</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">content</span><span class="pun">}</span><span class="pln"> 
      </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">toggleImportance</span><span class="pun">}&gt;{</span><span class="pln">label</span><span class="pun">}&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لاحظ كيف عرفنا محدد الصنف ضمن الصفة classname:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4393_23" style="">
<span class="pun">.</span><span class="pln">note </span><span class="pun">{</span><span class="pln">
  color</span><span class="pun">:</span><span class="pln"> grey</span><span class="pun">;</span><span class="pln">
  padding</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5px</span><span class="pun">;</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">15px</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لن تتأثر الآن عناصر <code>li</code> الأخرى الآن بهذه القاعدة بل فقط العناصر التي تظهر الملاحظات.
</p>

<h2>
	رسائل خطأ بمظهر أفضل
</h2>

<p>
	استخدمنا سابقا التابع <code>alert</code> لإظهار رسالة خطأ عندما يحاول المستخدم تغيير أهمية ملاحظة محذوفة. لننشئ الآن مكوِّنًا خاصًا بإظهار رسائل الخطأ:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4393_25" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Notification</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> message </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">message </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">null</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div className</span><span class="pun">=</span><span class="str">"error"</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">message</span><span class="pun">}</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لن يصيّر شيء على الشاشة إن كانت رسالة الخطأ فارغة، بينما ستصيّر الرسالة في بقية الحالات داخل عنصر <code>div</code>. لنضف قطعة حالة تدعى <code>errorMessage</code> إلى المكوِّن <code>App</code>. ونعطها رسالة خطأ ما كقيمة ابتدائية لنتمكن من اختبارها مباشرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4393_27" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">notes</span><span class="pun">,</span><span class="pln"> setNotes</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">([])</span><span class="pln"> 
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">newNote</span><span class="pun">,</span><span class="pln"> setNewNote</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">showAll</span><span class="pun">,</span><span class="pln"> setShowAll</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">errorMessage</span><span class="pun">,</span><span class="pln"> setErrorMessage</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="str">'some error happened...'</span><span class="pun">)</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Notes</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Notification</span><span class="pln"> message</span><span class="pun">={</span><span class="pln">errorMessage</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setShowAll</span><span class="pun">(!</span><span class="pln">showAll</span><span class="pun">)}&gt;</span><span class="pln">
          show </span><span class="pun">{</span><span class="pln">showAll </span><span class="pun">?</span><span class="pln"> </span><span class="str">'important'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">'all'</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">      
      </span><span class="com">// ...</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لنضف قاعدة تنسيق جديدة باسم error تناسب رسالة الخطأ:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4393_29" style="">
<span class="pun">.</span><span class="pln">error </span><span class="pun">{</span><span class="pln">
  color</span><span class="pun">:</span><span class="pln"> red</span><span class="pun">;</span><span class="pln">
  background</span><span class="pun">:</span><span class="pln"> lightgrey</span><span class="pun">;</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">20px</span><span class="pun">;</span><span class="pln">
  border</span><span class="pun">-</span><span class="pln">style</span><span class="pun">:</span><span class="pln"> solid</span><span class="pun">;</span><span class="pln">
  border</span><span class="pun">-</span><span class="pln">radius</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5px</span><span class="pun">;</span><span class="pln">
  padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10px</span><span class="pun">;</span><span class="pln">
  margin</span><span class="pun">-</span><span class="pln">bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10px</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سنضيف الآن آلية لظهور رسالة الخطأ، وذلك بتعديل شيفرة الدالة <code>toggleImportanceOf</code> على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4393_31" style="">
<span class="pln">  </span><span class="kwd">const</span><span class="pln"> toggleImportanceOf </span><span class="pun">=</span><span class="pln"> id </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> note </span><span class="pun">=</span><span class="pln"> notes</span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="pln">n </span><span class="pun">=&gt;</span><span class="pln"> n</span><span class="pun">.</span><span class="pln">id </span><span class="pun">===</span><span class="pln"> id</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> changedNote </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">...</span><span class="pln">note</span><span class="pun">,</span><span class="pln"> important</span><span class="pun">:</span><span class="pln"> </span><span class="pun">!</span><span class="pln">note</span><span class="pun">.</span><span class="pln">important </span><span class="pun">}</span><span class="pln">

    noteService
      </span><span class="pun">.</span><span class="pln">update</span><span class="pun">(</span><span class="pln">changedNote</span><span class="pun">).</span><span class="pln">then</span><span class="pun">(</span><span class="pln">returnedNote </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        setNotes</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> note</span><span class="pun">.</span><span class="pln">id </span><span class="pun">!==</span><span class="pln"> id </span><span class="pun">?</span><span class="pln"> note </span><span class="pun">:</span><span class="pln"> returnedNote</span><span class="pun">))</span><span class="pln">
      </span><span class="pun">})</span><span class="pln">
      </span><span class="pun">.</span><span class="kwd">catch</span><span class="pun">(</span><span class="pln">error </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        setErrorMessage</span><span class="pun">(</span><span class="pln">
            </span><span class="pun">`</span><span class="typ">Note</span><span class="pln"> </span><span class="str">'${note.content}'</span><span class="pln"> was already removed from server</span><span class="pun">`</span><span class="pln">
        </span><span class="pun">)</span><span class="pln">
        setTimeout</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            setErrorMessage</span><span class="pun">(</span><span class="kwd">null</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">},</span><span class="pln"> </span><span class="lit">5000</span><span class="pun">)</span><span class="pln">
        setNotes</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">n </span><span class="pun">=&gt;</span><span class="pln"> n</span><span class="pun">.</span><span class="pln">id </span><span class="pun">!==</span><span class="pln"> id</span><span class="pun">))</span><span class="pln">
      </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">}</span></pre>

<p>
	عندما يقع الخطأ، نضيف وصفًا لهذا الخطأ ضمن قطعة الحالة <code>errorMessage</code>. وفي نفس اللحظة سيعمل مؤقت يعيد قيمة الحالة إلى null (لا شيء) بعد خمس ثوان. ستبدو النتيجة كالتالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/error_message_style_001.png.b89ebaf09354d327b93f93372f3bb65b.png" data-fileid="55270" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="55270" data-unique="6ygarpr4j" src="https://academy.hsoub.com/uploads/monthly_2021_01/error_message_style_001.png.b89ebaf09354d327b93f93372f3bb65b.png" alt="error_message_style_001.png"></a>
</p>

<p>
	يمكن الحصول على شيفرة التطبيق بوضعه الحالي في الفرع part2-7 على <a href="https://github.com/fullstack-hy2020/part2-notes/tree/part2-7" rel="external nofollow">github</a>.
</p>

<h2>
	التنسيق ضمن السياق
</h2>

<p>
	تعطي React الإمكانية لتنسيق العناصر مباشرة ضمن سياق الشيفرة أو ما يدعى التنسيق ضمن السياق <a href="https://react-cn.github.io/react/tips/inline-styles.html" rel="external nofollow">inline styles</a>. والغاية من ذلك أن نزوّد كل مكوِّن في React بمجموعة من التنسيقات المعرفة داخل كائن JavaScript من خلال الصفة <a href="http://(https://wiki.hsoub.com/React/dom_elements#style" rel="external nofollow">style</a>. تعرّف التنسيقات بشكل مختلف قليلًا في JavaScript عما هي عليه في ملف CSS. فلو أردنا أن يظهر عنصر ما باللون الأخضر وأن يكون مائلًا حجمه 16 بيكسل، سنجد أن هذه القاعدة ستكتب في CSS بالشكل:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_4393_34" style="">
<span class="pun">{</span><span class="pln">
  color</span><span class="pun">:</span><span class="pln"> green</span><span class="pun">;</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">style</span><span class="pun">:</span><span class="pln"> italic</span><span class="pun">;</span><span class="pln">
  font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">16px</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	بينما في React كتنسيق مباشر في المكان ستكون كالتالي:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_4393_36" style="">
<span class="pln"> </span><span class="pun">{</span><span class="pln">
  color</span><span class="pun">:</span><span class="pln"> </span><span class="str">'green'</span><span class="pun">,</span><span class="pln">
  fontStyle</span><span class="pun">:</span><span class="pln"> </span><span class="str">'italic'</span><span class="pun">,</span><span class="pln">
  fontSize</span><span class="pun">:</span><span class="pln"> </span><span class="lit">16</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لاحظ كيف عرّفت كل خاصة تنسيق بشكل مستقل ضمن كائن JavaScript، وأن القيم العددية المقدّرة بالبيكسل يمكن تعريفها ببساطة كأعداد صحيحة. أحد الاختلافات الرئيسة بين الأسلوبين هو أن كتابة الخصائص بطريقة أسياخ الشواء (kebab case) المتبعة في CSS ستتغير إلى طريقة سنام الجمل (camelCase) في JavaScript.
</p>

<p>
	سنضيف أخيرًا كتلة سفلية لتطبيقنا بإنشاء مكوِّن جديد يدعى <code>Footer</code> وننسقه في مكانه كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4393_38" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Footer</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> footerStyle </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    color</span><span class="pun">:</span><span class="pln"> </span><span class="str">'green'</span><span class="pun">,</span><span class="pln">
    fontStyle</span><span class="pun">:</span><span class="pln"> </span><span class="str">'italic'</span><span class="pun">,</span><span class="pln">
    fontSize</span><span class="pun">:</span><span class="pln"> </span><span class="lit">16</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div style</span><span class="pun">={</span><span class="pln">footerStyle</span><span class="pun">}&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">br </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">em</span><span class="pun">&gt;</span><span class="typ">Note</span><span class="pln"> app</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Department</span><span class="pln"> of </span><span class="typ">Computer</span><span class="pln"> </span><span class="typ">Science</span><span class="pun">,</span><span class="pln"> </span><span class="typ">University</span><span class="pln"> of </span><span class="typ">Helsinki</span><span class="pln"> </span><span class="lit">2020</span><span class="pun">&lt;/</span><span class="pln">em</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Notes</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">

      </span><span class="pun">&lt;</span><span class="typ">Notification</span><span class="pln"> message</span><span class="pun">={</span><span class="pln">errorMessage</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">

      </span><span class="com">// ...  </span><span class="pln">

      </span><span class="pun">&lt;</span><span class="typ">Footer</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يأتي التنسيق ضمن السياق بمحدودية معينة. فلا يمكن استخدام أصناف الحالات الزائفة <a href="https://wiki.hsoub.com/CSS#.D8.A7.D9.84.D8.A3.D8.B5.D9.86.D8.A7.D9.81_.D8.A7.D9.84.D8.B2.D8.A7.D8.A6.D9.81.D8.A9" rel="external">pseudo-classes</a> مباشرة على سبيل المثال. إنّ استخدام التنسيق ضمن السياق وبعض الطرق الأخرى في تعريف التنسيقات ضمن مكوِّنات React تتعارض مع الأعراف المتبعة سابقًا. فقد اعتبر فصل التنسيقات CSS عن المحتوى HTML وعن الوظائف JavaScript هو العمل المثالي. وكان الهدف من ذلك وفقًا لأفكار المدرسة التقليدية، هو كتابة كل منها في ملفه الخاص.
</p>

<p>
	تعارض فلسفة React تمامًا الفكرة السابقة من منطلق أن عملية الفصل في ملفات مختلفة لن تتماشى مع التطبيقات الأكبر. فتقسيم التطبيقات من وجهة نظر React يجب أن يكون على أساس المهام الوظيفية للمكوِّنات التي تمثل التطبيق ككل. فالمكوِّنات هي من يعطي التطبيق قدرته الوظيفية. حيث تستخدم المكوِّنات HTML لبناء المحتوى وتستخدم دوال JavaScript لتنفيذ وظائف التطبيق بالإضافة إلى تنسيق المكوِّنات. والهدف من كل ذلك بناء مكوِّن مستقل بحد ذاته يمكن إعادة استخدامه قدر الإمكان.
</p>

<p>
	يمكن الحصول على شيفرة التطبيق بوضعه الحالي في الفرع part2-8 على <a href="https://github.com/fullstack-hy2020/part2-notes/tree/part2-8" rel="external nofollow">github</a>.
</p>

<h2>
	التمارين 2.19- 2.20
</h2>

<h3>
	2.19 دليل الهاتف: الخطوة 11
</h3>

<p>
	استخدم المثال في فقرة رسائل خطأ بمظهر أفضل من هذا الفصل، كدليل يساعدك في إظهار تنبيه لعدة ثوان، بعد تنفيذ عملية بشكل ناجح (إضافة اسم أو رقم).
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/phonebook_step11_002.png.1426df048ff728752a1e185c505fa6fb.png" data-fileid="55271" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="55271" data-unique="4e0hn7luz" src="https://academy.hsoub.com/uploads/monthly_2021_01/phonebook_step11_002.png.1426df048ff728752a1e185c505fa6fb.png" alt="phonebook_step11_002.png"></a>
</p>

<h3>
	2.20 دليل الهاتف: الخطوة 12 *
</h3>

<p>
	افتح تطبيقك ضمن متصفحين. لاحظ إن حذفت شخصًا في المتصفح الأول، ثم أردت بعدها بقليل تغيير رقم الشخص نفسه في المتصفح الثاني ستظهر لك رسالة الخطأ التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/phonebook_step12_success_003.png.f2bf957a6bc247757b1e2c2be3383e24.png" data-fileid="55273" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="55273" data-unique="7lf9ejzyf" src="https://academy.hsoub.com/uploads/monthly_2021_01/phonebook_step12_success_003.png.f2bf957a6bc247757b1e2c2be3383e24.png" alt="phonebook_step12_success_003.png"></a>
</p>

<p>
	أصلح هذه المشكلة بالاستفادة من المثال في فقرة <a href="https://academy.hsoub.com/programming/javascript/react/%D8%AA%D8%BA%D9%8A%D9%8A%D8%B1-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%B9%D9%84%D9%89-%D8%A7%D9%84%D8%AE%D8%A7%D8%AF%D9%85-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-react-r1097/" rel="">الوعود والأخطاء</a> في القسم 2. عدّل تطبيقك بحيث تظهر رسالة خطأ للمستخدم تخبره بفشل العملية. وتذكر أن تظهر رسالتي النجاح والفشل بشكلين مختلفين.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/phonebook_step12_fail_004.png.03f1c8fbcb780b86832ce50810e428bf.png" data-fileid="55272" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="55272" data-unique="i3zx6hdkw" src="https://academy.hsoub.com/uploads/monthly_2021_01/phonebook_step12_fail_004.png.03f1c8fbcb780b86832ce50810e428bf.png" alt="phonebook_step12_fail_004.png"></a>
</p>

<p>
	<strong>ملاحظة</strong>: يجب أن تظهر رسالة الخطأ حتى لو تمت معالجة الخطأ.
</p>

<p>
	وهكذا نصل إلى التمرين الأخير في هذا القسم، وقد حان الوقت لتسليم الحلول على GitHub. لا تنسى أن تشير إلى التمارين على أنها منجزة ضمن <a href="https://studies.cs.helsinki.fi/stats/courses/fullstackopen" rel="external nofollow">منظومة تسليم التمارين</a>.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://fullstackopen.com/en/part2/adding_styles_to_react_app" rel="external nofollow">Adding styles to react app</a> من سلسلة <a href="https://fullstackopen.com/en/" rel="external nofollow">Deep Dive Into Modern Web Development</a>
</p>
]]></description><guid isPermaLink="false">1098</guid><pubDate>Sun, 10 Jan 2021 13:00:00 +0000</pubDate></item><item><title>&#x62A;&#x63A;&#x64A;&#x64A;&#x631; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; &#x639;&#x644;&#x649; &#x627;&#x644;&#x62E;&#x627;&#x62F;&#x645; &#x641;&#x64A; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; React</title><link>https://academy.hsoub.com/programming/javascript/react/%D8%AA%D8%BA%D9%8A%D9%8A%D8%B1-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%B9%D9%84%D9%89-%D8%A7%D9%84%D8%AE%D8%A7%D8%AF%D9%85-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-react-r1097/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_01/p11-2.jpg.01b80cb12c0f9c9cee3b9c56c0dd0d8b.jpg" /></p>

<p>
	من الطبيعي عندما ننشئ ملاحظات جديدة في تطبيقنا، أن نحفظ هذه الملاحظات على الخادم. تَعتبِر حزمة خادم JSON نفسها على أنها واجهة REST أو RESTful كما ورد في توثيقها:
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p>
		احصل على واجهة تطبيقات وهمية متوافقة مع REST وبدون كتابة أية شيفرات خلال 30 ثانية.
	</p>
</blockquote>

<p>
	لا يتطابق توصيف خادم JSON تمامًا مع <a href="https://en.wikipedia.org/wiki/Representational_state_transfer" rel="external nofollow">تعريف</a> واجهة التطبيقات REST، كما هي حال معظم الواجهات التي تدّعي بأنها متوافقة تمامًا مع REST. سنطلع أكثر على REST في القسم التالي من المنهاج، لكن من المهم أن نتعلم في هذه المرحلة بعض المعايير التوافقية المستخدمة من قبل خادم JSON والواجهة REST بشكل عام. وسنلقي نظرة خاصة على الاستخدام التوافقي <a href="https://github.com/typicode/json-server#routes" rel="external nofollow">للمسارات</a> (Routes) وهي الروابط وطلبات HTTP وفق مفاهيم REST.
</p>

<h2>
	واجهة التطبيقات REST
</h2>

<p>
	نشير إلى الكائنات التي تمثل بيانات منفردة -كالملاحظات في تطبيقنا- باسم الموارد (resources) وفقًا لمصطلحات REST. ولكل مورد مكانه المحدد والوحيد الذي يرتبط به (URL الخاص به). وبناء على معيار عام يعتمده خادم JSON، سنتمكن من الحصول على ملاحظة واحدة من الملاحظات من المورد الموجود في الموقع notes/3. حيث يمثل الرقم 3 المعرِّف الفريد للمورد. ومن ناحية أخرى سيمثل موقع المورد notes تجمّع موارد (resource collection) يضم كل الملاحظات.
</p>

<p>
	تُحضَر الموارد من الخادم عن طريق الطلبات HTTP-GET. فالطلب HTTP-GET المرسل إلى الموقع notes/3 سيعيد الملاحظة التي معرِّفها 3. بينما لو أُرسل نفس الطلب إلى الموقع notes سيعيد لائحة بالملاحظات الموجودة.
</p>

<p>
	يُنشأ مورد جديد لتخزين ملاحظة بإرسال طلب HTTP-POST إلى الموقع notes، وفقًا لمعيار REST الذي يتوافق معه خادم JSON. ترسل البيانات إلى المورد الجديد "الملاحظة الجديدة" ضمن جسم الطلب. يفرض خادم JSON إرسال جميع البيانات بتنسيق JSON. ويقضي ذلك عمليًا أن تكون البيانات على شكل نص منسق بشكل صحيح وأن يضم الطلب ترويسة "نوع المحتوى" بداخلها القيمة application/json.
</p>

<h2>
	إرسال البيانات إلى الخادم
</h2>

<p>
	سنعدّل معالج الحدث المسؤول عن إنشاء ملاحظة جديدة كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4984_7" style="">
<span class="pln">addNote </span><span class="pun">=</span><span class="pln"> event </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> noteObject </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> newNote</span><span class="pun">,</span><span class="pln">
    date</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">(),</span><span class="pln">
    important</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">()</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0.5</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  axios    
    </span><span class="pun">.</span><span class="pln">post</span><span class="pun">(</span><span class="str">'http://localhost:3001/notes'</span><span class="pun">,</span><span class="pln"> noteObject</span><span class="pun">)</span><span class="pln">
      </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">response</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">})}</span></pre>

<p>
	لقد أنشأنا كائنًا جديدًا يحتوي بيانات الملاحظة لكننا أغفلنا الخاصية <code>id</code>، فمن الأفضل أن يولد الخادم قيم المعرّفات الفريدة للموارد <code>id</code>. يُرسل الكائن بعد ذلك إلى الخادم باستخدام التابع <code>post</code> من المكتبة axios. ثم يطبع معالج الحدث المعرّف مسبقًا استجابة الخادم على الطرفية. ستعرض الطرفية البيانات التالية عند إنشاء ملاحظة جديدة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/data_from_new_note_001.png.2c4cd1f27d1cd58bc782c1a83a590a88.png" data-fileid="55265" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="55265" data-unique="3rsjm4fa7" src="https://academy.hsoub.com/uploads/monthly_2021_01/data_from_new_note_001.png.2c4cd1f27d1cd58bc782c1a83a590a88.png" alt="data_from_new_note_001.png"></a>
</p>

<p>
	يخزَّن مورد الملاحظة الجديدة في الخاصية <code>data</code> لكائن الاستجابة الذي يعيده الخادم. من المفيد أحيانًا تحرّي طلبات HTTP في النافذة Network من طرفية تطوير المتصفح الخاص بك والتي استخدمناها كثيرًا في مقال <a href="https://academy.hsoub.com/programming/javascript/react/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r1071/" rel="">أساسيات بناء تطبيقات الويب</a>.
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="55269" data-unique="lsv53mpqt" src="https://academy.hsoub.com/uploads/monthly_2021_01/using_console_network_002.png.41ae5baeb592ab8bf17c193c5432fda2.png" alt="using_console_network_002.png"></p>

<p>
	باستخدام المفتش inspector سنتمكن من تحري الترويسات التي ترسل عبر طلبات post فيما لو كانت هي تمامًا ما نريده، أو أنّ القيم التي تحملها صحيحة. تسنِد axios تلقائيًا القيمة "application/json" إلى ترويسة "نوع-المحتوى"، طالما أن البيانات المرسلة عبر الطلب post هي كائن JavaScript.
</p>

<p>
	لم تصيّر الملاحظة الجديدة على الشاشة بعد، وذلك لأننا لم نحدث حالة المكوِّن<code>App</code> بعد إنشائها، لذا سنصلح الأمر:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4984_9" style="">
<span class="pln">addNote </span><span class="pun">=</span><span class="pln"> event </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> noteObject </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> newNote</span><span class="pun">,</span><span class="pln">
    date</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">(),</span><span class="pln">
    important</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">()</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0.5</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  axios
    </span><span class="pun">.</span><span class="pln">post</span><span class="pun">(</span><span class="str">'http://localhost:3001/notes'</span><span class="pun">,</span><span class="pln"> noteObject</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      setNotes</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">concat</span><span class="pun">(</span><span class="pln">response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">))</span><span class="pln">
      setNewNote</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تضاف الملاحظة الجديدة القادمة من الخادم إلى قائمة الملاحظات في تطبيقنا باستخدام الدالة <code>setNotes</code>، وبعدها تصفّر الشيفرة نموذج إنشاء الملاحظات. وتذكر <a href="https://academy.hsoub.com/programming/javascript/react/%D8%AD%D8%A7%D9%84%D8%A7%D8%AA-%D8%A3%D8%B9%D9%82%D8%AF-%D9%84%D9%84%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-%D9%88%D8%AA%D9%86%D9%82%D9%8A%D8%AD-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-react-r1075/" rel="">أحد التفاصيل المهمة</a> عند استخدام التابع <code>concat</code>، بأنه لا يغيّر المصفوفة الأصلية وبالتالي لا يغيّر حالة المكوِّن بل ينشئ نسخة عن القائمة الأصلية. سيبدأ تأثير الخادم على سلوك تطبيقنا لحظة إعادته البيانات. وسنكون مباشرة أمام تحديات جديدة منها على سبيل المثال عدم التزامن في الاتصال. لهذا ستظهر الحاجة إلى استراتيجيات جديدة للتنقيح بالإضافة إلى الطباعة على الطرفية، وغيرها من الطرق التنقيح التي تزداد أهميتها مع الوقت. إضافة إلى ذلك لابد من فهمٍ كافٍ لمبادئ بيئة تشغيل JavaScript ومكوِّنات React. فلن يكفي التخمين فقط في حل المشاكل. ومن المفيد أغلب الأحيان التحقق من حالة الخادم من خلال المتصفح:
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="55268" data-unique="ls5594uum" src="https://academy.hsoub.com/uploads/monthly_2021_01/server_inspect_003..png.522b83a0752d011bebe9875383fdd5df.png" alt="server_inspect_003..png"></p>

<p>
	حيث يمكننا التحقق من أنّ جميع البيانات التي أرسلناها قد استقبلها الخادم.
</p>

<p>
	سنتعلم في القسم التالي من المنهاج كيف نتعامل بمنطقنا الخاص مع الواجهة الخلفية، وسنلقي نظرة أقرب على أدوات مهمة مثل <a href="https://www.postman.com" rel="external nofollow">postman</a> التي ستساعد في تنقيح تطبيقات الواجهة الخلفية. يكفينا حاليًا تحرّي حالة الخادم من خلال المتصفح.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p>
		<strong>ملاحظة</strong>: يضيف المتصفح في نسختنا الحالية من التطبيق بيانات إنشاء الملاحظة الجديدة. لكن قد تكون ساعة الحاسب خاطئة، لذا من الأفضل أن نترك مهمة تحديد الوقت للخادم. وهذا بالضبط ما سنفعله في القسم القادم من المنهاج.
	</p>
</blockquote>

<p>
	يمكن الحصول على شيفرة التطبيق بوضعه الحالي في الفرع part2-5 على <a href="https://github.com/fullstack-hy2020/part2-notes/tree/part2-5" rel="external nofollow">github</a>.
</p>

<h2>
	تغيير مؤشر أهمية الملاحظة
</h2>

<p>
	لنضف زرًا إلى كل ملاحظة بحيث نتمكن من تغيير حالتها بشكل مستمر، ستتغير الشيفرة في المكوِّن <code>Note</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4984_11" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Note</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> note</span><span class="pun">,</span><span class="pln"> toggleImportance </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> label </span><span class="pun">=</span><span class="pln"> note</span><span class="pun">.</span><span class="pln">important
    </span><span class="pun">?</span><span class="pln"> </span><span class="str">'make not important'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">'make important'</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">content</span><span class="pun">}</span><span class="pln"> 
      </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">toggleImportance</span><span class="pun">}&gt;{</span><span class="pln">label</span><span class="pun">}&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لقد أضفنا عنصر <code>button</code> إلى المكوِّن، وعيّنا الدالة <code>toggleImportance</code> كمعالج لحدث النقر على الزر، ومررناه إلى المكوِّن من خلال الخصائص. يعرّف المكوِّن <code>App</code> نسخة ابتدائية من معالج الحدث <code>toggleImportanceOf</code>، ثم يمرره إلى كل مكوِّن <code>Note</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4984_13" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">notes</span><span class="pun">,</span><span class="pln"> setNotes</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">([])</span><span class="pln"> 
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">newNote</span><span class="pun">,</span><span class="pln"> setNewNote</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">showAll</span><span class="pun">,</span><span class="pln"> setShowAll</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln">

  </span><span class="com">// ...</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> toggleImportanceOf </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">id</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'importance of '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> id </span><span class="pun">+</span><span class="pln"> </span><span class="str">' needs to be toggled'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Notes</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setShowAll</span><span class="pun">(!</span><span class="pln">showAll</span><span class="pun">)}&gt;</span><span class="pln">
          show </span><span class="pun">{</span><span class="pln">showAll </span><span class="pun">?</span><span class="pln"> </span><span class="str">'important'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">'all'</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">      
      </span><span class="pun">&lt;</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">notesToShow</span><span class="pun">.</span><span class="pln">map</span><span class="pun">((</span><span class="pln">note</span><span class="pun">,</span><span class="pln"> i</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> 
          </span><span class="pun">&lt;</span><span class="typ">Note</span><span class="pln">
            key</span><span class="pun">={</span><span class="pln">i</span><span class="pun">}</span><span class="pln">
            note</span><span class="pun">={</span><span class="pln">note</span><span class="pun">}</span><span class="pln"> 
            toggleImportance</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> toggleImportanceOf</span><span class="pun">(</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">)}</span><span class="pln">          </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">)}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="com">// ...</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لاحظ في الشيفرة السابقة كيف ستحصل كل ملاحظة على معالج حدث فريد خاص بها، ذلك أن قيمة <code>id</code> لكل ملاحظة هي قيمة فريدة. فلو افترضنا أن قيمة id لملاحظة هي 3، ستكون دالة معالج الحدث الخاصة بها والتي تعيدها الدالة <code>(toggleImportance(note.id</code> من الشكل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4984_15" style="">
<span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'importance of 3 needs to be toggled'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">}</span></pre>

<p>
	وتذكر هنا أننا استخدمنا أسلوبًا مشابهًا للغة Java في طباعة النص على الطرفية، وذلك بجمع السلاسل النصية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4984_17" style="">
<span class="pln">console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'importance of '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> id </span><span class="pun">+</span><span class="pln"> </span><span class="str">' needs to be toggled'</span><span class="pun">)</span></pre>

<p>
	كما يمكنك استخدام <a href="https://wiki.hsoub.com/JavaScript/Template_Literals" rel="external">القالب النصي</a> الذي أضيف مع ES6، لكتابة سلسلة نصية مماثلة وبطريقة أجمل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4984_21" style="">
<span class="pln">console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(`</span><span class="pln">importance of $</span><span class="pun">{</span><span class="pln">id</span><span class="pun">}</span><span class="pln"> needs to be toggled</span><span class="pun">`)</span></pre>

<p>
	إذا وضعنا عبارة JavaScript بين قوسين معقوصين وقبلها رمز الدولار($) ستُنفَّذ هذه العبارة ضمن السلسلة النصية وتُطبَع قيمتها. وانتبه جيدًا إلى علامات التنصيص المستخدمة في القالب النصي (```
</p>

<p>
	نستطيع التعديل على الملاحظة المخزنة على خادم JSON بطريقتين مختلفتين، وذلك بإرسال طلبات HTTP إلى الموقع الفريد للملاحظة. إذ بالإمكان أن نستبدل الملاحظة بالكامل من خلال الطلب HTTP-PUT، أو أن نغير بعض حقولها من خلال الطلب HTTP-PATCH.
</p>

<p>
	سيبدو الشكل النهائي لدالة معالج الحدث كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4984_23" style="">
<span class="kwd">const</span><span class="pln"> toggleImportanceOf </span><span class="pun">=</span><span class="pln"> id </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> url </span><span class="pun">=</span><span class="pln"> </span><span class="pun">`</span><span class="pln">http</span><span class="pun">:</span><span class="com">//localhost:3001/notes/${id}`</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> note </span><span class="pun">=</span><span class="pln"> notes</span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="pln">n </span><span class="pun">=&gt;</span><span class="pln"> n</span><span class="pun">.</span><span class="pln">id </span><span class="pun">===</span><span class="pln"> id</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> changedNote </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">...</span><span class="pln">note</span><span class="pun">,</span><span class="pln"> important</span><span class="pun">:</span><span class="pln"> </span><span class="pun">!</span><span class="pln">note</span><span class="pun">.</span><span class="pln">important </span><span class="pun">}</span><span class="pln">

  axios</span><span class="pun">.</span><span class="pln">put</span><span class="pun">(</span><span class="pln">url</span><span class="pun">,</span><span class="pln"> changedNote</span><span class="pun">).</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    setNotes</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> note</span><span class="pun">.</span><span class="pln">id </span><span class="pun">!==</span><span class="pln"> id </span><span class="pun">?</span><span class="pln"> note </span><span class="pun">:</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">))</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يمتلئ جسم الدالة السابقة بالتفاصيل الهامة. حيث يعرّف السطر الأول الموقع الفريد لكل ملاحظة بناء على قيمة <code>id</code>. ويُستخدَم التابع <a href="https://wiki.hsoub.com/JavaScript/Array/find" rel="external">find</a> لإيجاد الملاحظة التي نرغب في تعديلها ثم تُسند قيمته إلى المتغير <code>note</code>. ثم ننشئ بعد ذلك كأئنًا جديدًا يمثل نسخة تطابق الملاحظة الأصلية باستثناء ما يتعلق بخاصية "الأهمية". قد يبدو لك إنشاء كائن جديد بأسلوب <a href="https://wiki.hsoub.com/JavaScript/Spread_Operator" rel="external">الكائن المنشور</a> غريبًا بعض الشيء:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4984_25" style="">
<span class="kwd">const</span><span class="pln"> changedNote </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">...</span><span class="pln">note</span><span class="pun">,</span><span class="pln"> important</span><span class="pun">:</span><span class="pln"> </span><span class="pun">!</span><span class="pln">note</span><span class="pun">.</span><span class="pln">important </span><span class="pun">}</span></pre>

<p>
	تنشئ التعليمة <code>{note...}</code> كائنًا جديدًا يحمل نسخًا عن جميع خصائص (حقول) الكائن <code>note</code>. وعند وضع الخصائص ضمن قوسين معقوصين بعد نشر الكائن على الشكل التالي {note, important: true …}، ستأخذ الخاصة <code>important</code> للكائن الجديد القيمة true. لكن انتبه إلى مثالنا السابق بأننا أخذنا القيمة المعاكسة للخاصة <code>important</code>. هناك نقاط أخرى لابد من الإشارة إليها، فلماذا مثلًا أنشأنا نسخة عن الملاحظة التي نريد تعديلها إن كان بالإمكان تنفيذ ذلك كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4984_27" style="">
<span class="kwd">const</span><span class="pln"> note </span><span class="pun">=</span><span class="pln"> notes</span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="pln">n </span><span class="pun">=&gt;</span><span class="pln"> n</span><span class="pun">.</span><span class="pln">id </span><span class="pun">===</span><span class="pln"> id</span><span class="pun">)</span><span class="pln">
note</span><span class="pun">.</span><span class="pln">important </span><span class="pun">=</span><span class="pln"> </span><span class="pun">!</span><span class="pln">note</span><span class="pun">.</span><span class="pln">important

axios</span><span class="pun">.</span><span class="pln">put</span><span class="pun">(</span><span class="pln">url</span><span class="pun">,</span><span class="pln"> note</span><span class="pun">).</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span></pre>

<p>
	لا نفضل استخدام هذا الأسلوب لأن المتغير <code>note</code> يمثل مرجعًا إلى أحد عناصر المصفوفة <code>notes</code> في حالة المكوِّن، وتذكّر أن لا تغيّر حالة المكوِّن بشكل مباشر في تطبيقات React. كما لن يحمل الكائن الجديد الناتج عن تغير الملاحظة بهذه الطريقة أي تغيير فعلي وهذا ما يسمى <a href="https://en.wikipedia.org/wiki/Object_copying#Shallow_copy" rel="external nofollow">النسخ السطحي</a>. ويعني هذا أنّ قيم النسخة الجديدة هي نفسها قيم الكائن القديم. حتى لو كانت قيم الكائن القديم هي كائنات بحد ذاتها، ستشير نسخها الموجودة في الكائن الجديد إلى نفس الكائنات القديمة.
</p>

<p>
	بالعودة إلى تفاصيل دالة معالج حدث تغيير أهمية الملاحظة، ستُرسل أخيرًا الملاحظة الجديدة إلى الخادم على شكل طلب HTTP-PUT، وتُستبدل الملاحظة القديمة. تضبط دالة الاستدعاء (إعادة النداء) حالة الملاحظات في المكوِّن من جديد على قيم المصفوفة التي تضم جميع الملاحظات ماعدا تلك التي تم استبدالها بالنسخة الجديدة التي يعيدها الخادم:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4984_29" style="">
<span class="pln">axios</span><span class="pun">.</span><span class="pln">put</span><span class="pun">(</span><span class="pln">url</span><span class="pun">,</span><span class="pln"> changedNote</span><span class="pun">).</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  setNotes</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> note</span><span class="pun">.</span><span class="pln">id </span><span class="pun">!==</span><span class="pln"> id </span><span class="pun">?</span><span class="pln"> note </span><span class="pun">:</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">))</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	وينجز ذلك باستخدام التابع <code>map</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4984_31" style="">
<span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> note</span><span class="pun">.</span><span class="pln">id </span><span class="pun">!==</span><span class="pln"> id </span><span class="pun">?</span><span class="pln"> note </span><span class="pun">:</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span></pre>

<p>
	يعيد التابع <code>map</code> مصفوفة جديدة عن طريق ربط كل عنصر من المصفوفة القديمة بعنصر من المصفوفة الجديدة. لكن إنشاء المصفوفة الجديدة في مثالنا كان شرطيًا، فإن تحقق الشرط التالي <code>note.id !==id</code> ننقل العنصر من المصفوفة القديمة إلى الجديدة، وإن لم يتحقق ستحل محلها الملاحظة الجديدة التي يعيدها الخادم. قد تبدو حيلة <code>map</code> هذه غريبةً قليلًا، لكنها تستحق التوقف عندها وفهمها لأننا سنستخدمها مرات عدة لاحقًا.
</p>

<h2>
	نقل تعليمات الاتصال مع الواجهة الخلفية إلى وحدة منفصلة
</h2>

<p>
	لقد أصبح المكوِّن<code>App</code> مليئًا بالشيفرات بعد إضافة الاتصال مع الواجهة الخلفية. وانسجامًا مع <a href="https://en.wikipedia.org/wiki/Single_responsibility_principle" rel="external nofollow">مبدأ المسؤولية الفردية</a>، وجدنا من الحكمة أن ننقل الشيفرات المتعلقة بالاتصال إلى وحدة منفصلة خاصة بها. لننشئ مجلدًا باسم services ضمن المجلد src وننشئ ضمنه الملف notes.js:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4984_33" style="">
<span class="kwd">import</span><span class="pln"> axios from </span><span class="str">'axios'</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> baseUrl </span><span class="pun">=</span><span class="pln"> </span><span class="str">'http://localhost:3001/notes'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> getAll </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> axios</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="pln">baseUrl</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> create </span><span class="pun">=</span><span class="pln"> newObject </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> axios</span><span class="pun">.</span><span class="pln">post</span><span class="pun">(</span><span class="pln">baseUrl</span><span class="pun">,</span><span class="pln"> newObject</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> update </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">id</span><span class="pun">,</span><span class="pln"> newObject</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> axios</span><span class="pun">.</span><span class="pln">put</span><span class="pun">(`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">baseUrl</span><span class="pun">}/</span><span class="pln">$</span><span class="pun">{</span><span class="pln">id</span><span class="pun">}`,</span><span class="pln"> newObject</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
  getAll</span><span class="pun">:</span><span class="pln"> getAll</span><span class="pun">,</span><span class="pln"> 
  create</span><span class="pun">:</span><span class="pln"> create</span><span class="pun">,</span><span class="pln"> 
  update</span><span class="pun">:</span><span class="pln"> update 
</span><span class="pun">}</span></pre>

<p>
	تعيد الوحدة كائنًا من ثلاث دوال <code>getAll</code> و<code>create</code> و <code>update</code>، بالإضافة إلى خصائصه التي تتعامل مع الملاحظات. تعيد تلك الدوال وبشكل مباشر الوعود الناتجة عن تنفيذ توابع المكتبة axios والمتعلقة بالاتصال مع الخادم. يدرج المكوِّن <code>App</code> الوحدة الجديدة باستخدام التعليمة <code>import</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4984_35" style="">
<span class="kwd">import</span><span class="pln"> noteService from </span><span class="str">'./services/notes'</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span></pre>

<p>
	يمكن استخدام الدوال مباشرة بإسنادها للمتغير <code>noteService</code> عند إدراج الوحدة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4984_37" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">

  useEffect</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    noteService
        </span><span class="pun">.</span><span class="pln">getAll</span><span class="pun">()</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        setNotes</span><span class="pun">(</span><span class="pln">response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">},</span><span class="pln"> </span><span class="pun">[])</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> toggleImportanceOf </span><span class="pun">=</span><span class="pln"> id </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> note </span><span class="pun">=</span><span class="pln"> notes</span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="pln">n </span><span class="pun">=&gt;</span><span class="pln"> n</span><span class="pun">.</span><span class="pln">id </span><span class="pun">===</span><span class="pln"> id</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> changedNote </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">...</span><span class="pln">note</span><span class="pun">,</span><span class="pln"> important</span><span class="pun">:</span><span class="pln"> </span><span class="pun">!</span><span class="pln">note</span><span class="pun">.</span><span class="pln">important </span><span class="pun">}</span><span class="pln">

    noteService
        </span><span class="pun">.</span><span class="pln">update</span><span class="pun">(</span><span class="pln">id</span><span class="pun">,</span><span class="pln"> changedNote</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        setNotes</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> note</span><span class="pun">.</span><span class="pln">id </span><span class="pun">!==</span><span class="pln"> id </span><span class="pun">?</span><span class="pln"> note </span><span class="pun">:</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">))</span><span class="pln">
      </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> addNote </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> noteObject </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      content</span><span class="pun">:</span><span class="pln"> newNote</span><span class="pun">,</span><span class="pln">
      date</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">().</span><span class="pln">toISOString</span><span class="pun">(),</span><span class="pln">
      important</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">()</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0.5</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    noteService
        </span><span class="pun">.</span><span class="pln">create</span><span class="pun">(</span><span class="pln">noteObject</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        setNotes</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">concat</span><span class="pun">(</span><span class="pln">response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">))</span><span class="pln">
        setNewNote</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">App</span></pre>

<p>
	سننقل التطبيق خطوة إضافية إلى الأمام بحيث يتلقى المكوِّن <code>App</code> كائنًا يحتوي على الاستجابة الكاملة للخادم على طلب HTTP في حال استخدم المكوِّن الدوال السابقة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4984_41" style="">
<span class="pln">noteService
  </span><span class="pun">.</span><span class="pln">getAll</span><span class="pun">()</span><span class="pln">
  </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    setNotes</span><span class="pun">(</span><span class="pln">response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">})</span></pre>

<p>
	يستخدم المكوِّن <code>App</code> الخاصة <code>response.data</code> فقط من كائن الاستجابة. وبالتالي سيكون استخدام الوحدة مريحًا أكثر لو أمكننا أن نحصل على بيانات الاستجابة فقط بدلًا من الاستجابة كاملةً. ستبدو الشيفرة التي تنفذ ذلك على النحو:
</p>

<pre class="ipsCode">
noteService
  .getAll()
  .then(initialNotes =&gt; {
    setNotes(initialNotes)
  })
</pre>

<p>
	يمكننا إنجاز ذلك بتغيير الشيفرة في الوحدة على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4984_43" style="">
<span class="kwd">import</span><span class="pln"> axios from </span><span class="str">'axios'</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> baseUrl </span><span class="pun">=</span><span class="pln"> </span><span class="str">'http://localhost:3001/notes'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> getAll </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> request </span><span class="pun">=</span><span class="pln"> axios</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="pln">baseUrl</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> request</span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> create </span><span class="pun">=</span><span class="pln"> newObject </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> request </span><span class="pun">=</span><span class="pln"> axios</span><span class="pun">.</span><span class="pln">post</span><span class="pun">(</span><span class="pln">baseUrl</span><span class="pun">,</span><span class="pln"> newObject</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> request</span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> update </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">id</span><span class="pun">,</span><span class="pln"> newObject</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> request </span><span class="pun">=</span><span class="pln"> axios</span><span class="pun">.</span><span class="pln">put</span><span class="pun">(`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">baseUrl</span><span class="pun">}/</span><span class="pln">$</span><span class="pun">{</span><span class="pln">id</span><span class="pun">}`,</span><span class="pln"> newObject</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> request</span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
  getAll</span><span class="pun">:</span><span class="pln"> getAll</span><span class="pun">,</span><span class="pln"> 
  create</span><span class="pun">:</span><span class="pln"> create</span><span class="pun">,</span><span class="pln"> 
  update</span><span class="pun">:</span><span class="pln"> update 
</span><span class="pun">}</span></pre>

<p>
	وهكذا فإن دوال وحدة الاتصال لن تعيد وعود توابع axios مباشرة، بل تسند الوعد إلى المتغيّر <code>request</code> ثم تستدعي التابع <code>then</code> الموافق:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4984_45" style="">
<span class="kwd">const</span><span class="pln"> getAll </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> request </span><span class="pun">=</span><span class="pln"> axios</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="pln">baseUrl</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> request</span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	بالنسبة للسطر الأخير من الشيفرة السابقة فهو شكل أكثر اختصارًا للشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4984_47" style="">
<span class="kwd">const</span><span class="pln"> getAll </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> request </span><span class="pun">=</span><span class="pln"> axios</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="pln">baseUrl</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> request</span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">    
    </span><span class="kwd">return</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data
  </span><span class="pun">})}</span></pre>

<p>
	تعيد الدالة المعدّلة <code>getAll</code> وعدًا، وكذلك سيفعل التابع <code>then</code> الذي ينتج عن وعد <a href="https://wiki.hsoub.com/JavaScript/Promise/then" rel="external">ويعيد وعدًا</a>. فبعد أن نعرّف معامل التابع <code>then</code> ليعيد مباشرة بيانات الاستجابة <code>response.data</code> نكون قد حصلنا على غايتنا من استخدام الدالة <code>getAll</code>. إن نجح طلب HTTP سيعيد الوعد البيانات التي يرسلها الخادم ضمن استجابته للطلب.
</p>

<p>
	سنحدّث الآن شيفرة المكوِّن <code>App</code> ليعمل مع التغييرات التي أجريناها على وحدة الاتصال. سنبدأ بإصلاح دوال الاستدعاء التي تُمرّر كمعاملات إلى توابع الكائن <code>noteService</code> حتى تتمكن من إعادة بيانات الاستجابة من الخادم مباشرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4984_49" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">

  useEffect</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    noteService
      </span><span class="pun">.</span><span class="pln">getAll</span><span class="pun">()</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">initialNotes </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        setNotes</span><span class="pun">(</span><span class="pln">initialNotes</span><span class="pun">)</span><span class="pln">
      </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">},</span><span class="pln"> </span><span class="pun">[])</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> toggleImportanceOf </span><span class="pun">=</span><span class="pln"> id </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> note </span><span class="pun">=</span><span class="pln"> notes</span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="pln">n </span><span class="pun">=&gt;</span><span class="pln"> n</span><span class="pun">.</span><span class="pln">id </span><span class="pun">===</span><span class="pln"> id</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> changedNote </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">...</span><span class="pln">note</span><span class="pun">,</span><span class="pln"> important</span><span class="pun">:</span><span class="pln"> </span><span class="pun">!</span><span class="pln">note</span><span class="pun">.</span><span class="pln">important </span><span class="pun">}</span><span class="pln">

    noteService
      </span><span class="pun">.</span><span class="pln">update</span><span class="pun">(</span><span class="pln">id</span><span class="pun">,</span><span class="pln"> changedNote</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">returnedNote </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        setNotes</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> note</span><span class="pun">.</span><span class="pln">id </span><span class="pun">!==</span><span class="pln"> id </span><span class="pun">?</span><span class="pln"> note </span><span class="pun">:</span><span class="pln"> returnedNote</span><span class="pun">))</span><span class="pln">
      </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> addNote </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> noteObject </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      content</span><span class="pun">:</span><span class="pln"> newNote</span><span class="pun">,</span><span class="pln">
      date</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">().</span><span class="pln">toISOString</span><span class="pun">(),</span><span class="pln">
      important</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">()</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0.5</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    noteService
      </span><span class="pun">.</span><span class="pln">create</span><span class="pun">(</span><span class="pln">noteObject</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">returnedNote </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        setNotes</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">concat</span><span class="pun">(</span><span class="pln">returnedNote</span><span class="pun">))</span><span class="pln">
        setNewNote</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln">
      </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تبدو الأمور معقدة، وقد تزداد تعقيدًا عندما نحاول أن نتعمق في شرحها، لذلك حاول أن تطلع على هذا الموضوع أكثر. وبالطبع شرحت أكاديمية حسوب شرحًا وافيًا هذا الموقع في مقال، <a href="https://academy.hsoub.com/tags/%D8%AF%D9%84%D9%8A%D9%84%20%D8%AA%D8%B9%D9%84%D9%85%20%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA/" rel="">سلسلة الوعود في جافاسكربت</a> وستجد شرحًا <a href="https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/async%20%26%20performance/ch3.md" rel="external nofollow">وافيًا</a> ومطولًا عن الموضوع في المراجع الأجنبية مثلًا في كتاب "Async performance" وهو أحد كتب سلسلة <a href="https://github.com/getify/You-Dont-Know-JS/tree/1st-ed" rel="external nofollow">You do not know JS</a>.
</p>

<p>
	إنّ فكرة الوعود هي فكرة مركزية في تطوير تطبيقات JavaScript الحديثة، لذلك ننصحك بشدة أن تقضي وقتًا كافيًا في فهمها.
</p>

<h2>
	كتابة شيفرة أوضح عند تعريف الكائنات المجرّدة
</h2>

<p>
	تُصَدِّر الوحدة التي أنشأناها سابقًا والتي تعرّف خدمات تتعلق بالتعامل مع الملاحظات، كائنًا يمتلك الخصائص <code>getAll</code> و<code>create</code> و<code>update</code> والتي تسند إلى دوال مخصصة للتعامل مع الملاحظات. يبدو تعريف هذه الوحدة بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4984_52" style="">
<span class="kwd">import</span><span class="pln"> axios from </span><span class="str">'axios'</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> baseUrl </span><span class="pun">=</span><span class="pln"> </span><span class="str">'http://localhost:3001/notes'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> getAll </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> request </span><span class="pun">=</span><span class="pln"> axios</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="pln">baseUrl</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> request</span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> create </span><span class="pun">=</span><span class="pln"> newObject </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> request </span><span class="pun">=</span><span class="pln"> axios</span><span class="pun">.</span><span class="pln">post</span><span class="pun">(</span><span class="pln">baseUrl</span><span class="pun">,</span><span class="pln"> newObject</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> request</span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> update </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">id</span><span class="pun">,</span><span class="pln"> newObject</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> request </span><span class="pun">=</span><span class="pln"> axios</span><span class="pun">.</span><span class="pln">put</span><span class="pun">(`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">baseUrl</span><span class="pun">}/</span><span class="pln">$</span><span class="pun">{</span><span class="pln">id</span><span class="pun">}`,</span><span class="pln"> newObject</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> request</span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
  getAll</span><span class="pun">:</span><span class="pln"> getAll</span><span class="pun">,</span><span class="pln"> 
  create</span><span class="pun">:</span><span class="pln"> create</span><span class="pun">,</span><span class="pln"> 
  update</span><span class="pun">:</span><span class="pln"> update 
</span><span class="pun">}</span></pre>

<p>
	تصدَّر الوحدة الكائن التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4984_54" style="">
<span class="pun">{</span><span class="pln"> 
  getAll</span><span class="pun">:</span><span class="pln"> getAll</span><span class="pun">,</span><span class="pln"> 
  create</span><span class="pun">:</span><span class="pln"> create</span><span class="pun">,</span><span class="pln"> 
  update</span><span class="pun">:</span><span class="pln"> update 
</span><span class="pun">}</span></pre>

<p>
	تدعى العبارات التي تقع على يسار العمود في الشيفرة السابقة، مفاتيح الكائن. بينما تدعى العبارات التي تقع على اليمين بمتغيّرات الكائن والتي تُعرّف داخل الوحدة. وطالما أن المفاتيح والمتغيرات تحمل نفس التسمية، يمكننا صياغة الكائن بشكل أكثر إختصارًا:
</p>

<pre class="ipsCode">
{ 
  getAll, 
  create, 
  update 
}
</pre>

<p>
	وكنتيجة لذلك سيصبح تعريف الوحدة أبسط:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4984_56" style="">
<span class="kwd">import</span><span class="pln"> axios from </span><span class="str">'axios'</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> baseUrl </span><span class="pun">=</span><span class="pln"> </span><span class="str">'http://localhost:3001/notes'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> getAll </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> request </span><span class="pun">=</span><span class="pln"> axios</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="pln">baseUrl</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> request</span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> create </span><span class="pun">=</span><span class="pln"> newObject </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> request </span><span class="pun">=</span><span class="pln"> axios</span><span class="pun">.</span><span class="pln">post</span><span class="pun">(</span><span class="pln">baseUrl</span><span class="pun">,</span><span class="pln"> newObject</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> request</span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> update </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">id</span><span class="pun">,</span><span class="pln"> newObject</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> request </span><span class="pun">=</span><span class="pln"> axios</span><span class="pun">.</span><span class="pln">put</span><span class="pun">(`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">baseUrl</span><span class="pun">}/</span><span class="pln">$</span><span class="pun">{</span><span class="pln">id</span><span class="pun">}`,</span><span class="pln"> newObject</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> request</span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> getAll</span><span class="pun">,</span><span class="pln"> create</span><span class="pun">,</span><span class="pln"> update </span><span class="pun">}</span></pre>

<p>
	إنّ تعريف الكائن بهذه الصيغة المختصرة، يعني استخدامنا <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Property_definitions" rel="external nofollow">لميزة جديدة</a> قدمتها JavaScript عند إطلاق ES6، والتي ستمكننا من تعريف الكائنات التي تستخدم المتغيّرات بطريقة مختصرة أكثر. ولتوضيح هذه الميّزة، دعونا نتأمل حالة معينة تسند فيها القيم التالية إلى متغيرات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4984_58" style="">
<span class="kwd">const</span><span class="pln"> name </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Leevi'</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> age </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span></pre>

<p>
	لقد توجب علينا في النسخ القديمة من JavaScript أن نعرف الكائن على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4984_60" style="">
<span class="kwd">const</span><span class="pln"> person </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> name</span><span class="pun">,</span><span class="pln">
  age</span><span class="pun">:</span><span class="pln"> age
</span><span class="pun">}</span></pre>

<p>
	وطالما أن الخصائص والمتغيرات في الكائن لها نفس التسمية، سيكون كافيًا كتابة التعريف باستخدام ES6 كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4984_62" style="">
<span class="kwd">const</span><span class="pln"> person </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> name</span><span class="pun">,</span><span class="pln"> age </span><span class="pun">}</span></pre>

<p>
	ستكون النتيجة نفسها في الطريقتين، فكلاهما يعرفان كائنًا له خاصية تدعى <code>name</code> تحمل القيمة "Leevi" وخاصية تدعى "age" وتحمل القيمة 0.
</p>

<h2>
	الوعود والأخطاء
</h2>

<p>
	لو سمح تطبيقنا للمستخدم أن يحذف ملاحظات، فقد يواجه حالة يريد فيها تغيير أهمية ملاحظة محذوفة سابقًا من النظام. لنحاكي هذه الحالة بأن نطلب من الدالة <code>getAll</code> أن تعيد ملاحظة مكتوبة مسبقًا لكنها عمليًا غير موجودة على الخادم:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4984_64" style="">
<span class="kwd">const</span><span class="pln"> getAll </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> request </span><span class="pun">=</span><span class="pln"> axios</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="pln">baseUrl</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> nonExisting </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10000</span><span class="pun">,</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'This note is not saved to server'</span><span class="pun">,</span><span class="pln">
    date</span><span class="pun">:</span><span class="pln"> </span><span class="str">'2019-05-30T17:30:31.098Z'</span><span class="pun">,</span><span class="pln">
    important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> request</span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">.</span><span class="pln">concat</span><span class="pun">(</span><span class="pln">nonExisting</span><span class="pun">))</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	عندما نحاول تغيير أهمية تلك الملاحظة، ستظهر لنا رسالة خطأ على شاشة الطرفية مفادها أن الخادم قد استجاب لطلب HTTP برمز الحالة 404 (غير موجود).
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/console_not_found_004.png.429bda399ee93600d159dbd1884e99dd.png" data-fileid="55264" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="55264" data-unique="z752c6621" src="https://academy.hsoub.com/uploads/monthly_2021_01/console_not_found_004.png.429bda399ee93600d159dbd1884e99dd.png" alt="console_not_found_004.png"></a>
</p>

<p>
	لذلك ينبغي على التطبيق أن يمنع وقوع هذا النوع من الأخطاء. فلن يعرف المستخدم أنّ هذا الخطأ قد وقع، إلا إذا صدف وكانت طرفية التطوير في متصفحه مفتوحة. الطريقة الوحيدة التي يمكن أن يُلاحظ فيها وقوع الخطأ في التطبيق هو عدم تغيّّر أهمية الملاحظة بعد النقر على الزر.
</p>

<p>
	لقد أشرنا سابقًا في القسم الثاني أن للوعد ثلاث حالات مختلفة. حيث يُرفض الوعد إذا فشل طلب HTTP. لم <a href="https://wiki.hsoub.com/JavaScript/Promise/Using_promises" rel="external">يعالج</a> تطبيقنا الحالة التي يُرفض فيها الوعد. ويعالج ذلك بتزويد التابع <code>then</code> بدالة استدعاء أخرى، تُستدعى في مثل هذه الحالة. نستخدم عادة التابع <a href="https://wiki.hsoub.com/JavaScript/Promise/catch" rel="external">catch</a> لهذه الغاية ويعرّف كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4984_66" style="">
<span class="pln">axios
  </span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'http://example.com/probably_will_fail'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'success!'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">.</span><span class="kwd">catch</span><span class="pun">(</span><span class="pln">error </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'fail'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">})</span></pre>

<p>
	عندما يخفق الطلب، يستدعى معالج الحدث المعرف ضمن التابع <code>catch</code> الذي يوضع عادة في آخر سلسلة التوابع التي تتعامل مع الوعد. فعندما يرسل التطبيق طلب HTTP، سينشأ في الواقع ما يسمى <a href="https://academy.hsoub.com/programming/javascript/%D8%B3%D9%84%D8%B3%D9%84%D8%A9-%D8%A7%D9%84%D9%88%D8%B9%D9%88%D8%AF-promises-chaining-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r916/" rel="">سلسلة الوعد</a> كما في الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4984_68" style="">
<span class="pln">axios
  </span><span class="pun">.</span><span class="pln">put</span><span class="pun">(`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">baseUrl</span><span class="pun">}/</span><span class="pln">$</span><span class="pun">{</span><span class="pln">id</span><span class="pun">}`,</span><span class="pln"> newObject</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">changedNote </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ...</span><span class="pln">
  </span><span class="pun">})</span></pre>

<p>
	وهكذا يُستدعى التابع <code>catch</code> حالما يرمي أي تابع في سلسلة الوعد خطأ ويرفض الوعد:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4984_70" style="">
<span class="pln">axios
  </span><span class="pun">.</span><span class="pln">put</span><span class="pun">(`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">baseUrl</span><span class="pun">}/</span><span class="pln">$</span><span class="pun">{</span><span class="pln">id</span><span class="pun">}`,</span><span class="pln"> newObject</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">changedNote </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ...</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">
  </span><span class="pun">.</span><span class="kwd">catch</span><span class="pun">(</span><span class="pln">error </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'fail'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">})</span></pre>

<p>
	لنستفد من الميزة السابقة ولنعرّّف معالجًا للخطأ في المكوِّن <code>App</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4984_74" style="">
<span class="kwd">const</span><span class="pln"> toggleImportanceOf </span><span class="pun">=</span><span class="pln"> id </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> note </span><span class="pun">=</span><span class="pln"> notes</span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="pln">n </span><span class="pun">=&gt;</span><span class="pln"> n</span><span class="pun">.</span><span class="pln">id </span><span class="pun">===</span><span class="pln"> id</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> changedNote </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">...</span><span class="pln">note</span><span class="pun">,</span><span class="pln"> important</span><span class="pun">:</span><span class="pln"> </span><span class="pun">!</span><span class="pln">note</span><span class="pun">.</span><span class="pln">important </span><span class="pun">}</span><span class="pln">

  noteService
    </span><span class="pun">.</span><span class="pln">update</span><span class="pun">(</span><span class="pln">id</span><span class="pun">,</span><span class="pln"> changedNote</span><span class="pun">).</span><span class="pln">then</span><span class="pun">(</span><span class="pln">returnedNote </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      setNotes</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> note</span><span class="pun">.</span><span class="pln">id </span><span class="pun">!==</span><span class="pln"> id </span><span class="pun">?</span><span class="pln"> note </span><span class="pun">:</span><span class="pln"> returnedNote</span><span class="pun">))</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
    </span><span class="pun">.</span><span class="kwd">catch</span><span class="pun">(</span><span class="pln">error </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      alert</span><span class="pun">(</span><span class="pln">
          </span><span class="pun">`</span><span class="pln">the note </span><span class="str">'${note.content}'</span><span class="pln"> was already deleted from server</span><span class="pun">`</span><span class="pln">
      </span><span class="pun">)</span><span class="pln">
      setNotes</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">n </span><span class="pun">=&gt;</span><span class="pln"> n</span><span class="pun">.</span><span class="pln">id </span><span class="pun">!==</span><span class="pln"> id</span><span class="pun">))</span><span class="pln">
  </span><span class="pun">})}</span></pre>

<p>
	يُعلِمُ التطبيق المستخدمَ بوجود خطأ من خلال النافذة المنبثقة <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/alert" rel="external nofollow">alert</a>، وتستبعد الملاحظة المحذوفة من حالة التطبيق. ويتم استبعاد الملاحظة المحذوفة مسبقًا من حالة التطبيق باستخدام تابع المصفوفات <code>filter</code> والذي يعيد مصفوفة جديدة تضم فقط القيم التي ستعيدها الدالة -التي تُمرّر إليه كمعامل- على أنها صحيحة.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4984_76" style="">
<span class="pln">notes</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">n </span><span class="pun">=&gt;</span><span class="pln"> n</span><span class="pun">.</span><span class="pln">id </span><span class="pun">!==</span><span class="pln"> id</span><span class="pun">)</span></pre>

<p>
	قد لا يعتبر استخدام <code>alert</code> مناسبًا في تطبيقات React، لذلك سنتعلم لاحقًا طرقًا متقدمة أكثر في عرض الرسائل والتنبيهات. لا يعني ذلك أن لا نستخدم <code>alert</code> أبدًا فقد تكون مفيدة كنقطة انطلاق.
</p>

<p>
	يمكن الحصول على شيفرة التطبيق بوضعه الحالي في الفرع part2-6 على <a href="https://github.com/fullstack-hy2020/part2-notes/tree/part2-6" rel="external nofollow">github</a>.
</p>

<h2>
	التمارين 2.15-2.18
</h2>

<h3>
	2.15 دليل الهاتف: الخطوة 7
</h3>

<p>
	لنعد إلى تطبيق دليل الهاتف الذي بدأناه سابقًا. احفظ رقم الهاتف الذي ندخله في الخادم.
</p>

<h3>
	2.16 دليل الهاتف: الخطوة 8
</h3>

<p>
	انقل الشيفرات التي تؤمن الاتصال مع الواجهة الخلفية إلى وحدة خاصة بها، بالاستفادة من المثال الذي عرضناه سابقًا في هذا الجزء.
</p>

<h3>
	2.17 دليل الهاتف: الخطوة 9
</h3>

<p>
	امنح المستخدم إمكانية حذف المدخلات إلى دليل الهاتف. يمكن أن تنفذ ذلك باستخدام زر خاص يظهر بجوار كل اسم في الدليل. يمكنك الطلب من المستخدم تأكيد عملية الحذف باستخدام التابع <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm" rel="external nofollow">window.confirm</a>:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/phonebook_step9_005.png.330e8cb5f0bef9daa55b5b8c67dfbf0b.png" data-fileid="55266" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="55266" data-unique="s2noqklkx" src="https://academy.hsoub.com/uploads/monthly_2021_01/phonebook_step9_005.png.330e8cb5f0bef9daa55b5b8c67dfbf0b.png" alt="phonebook_step9_005.png"></a>
</p>

<p>
	يمكن حذف المورد المتعلق بشخص من الخادم باستخدام طلب HTTP-DELETE إلى موقع المورد. فلو أردت حذف الشخص الذي قيمة معرّفه <code>id</code> هي 2، نفذ ذلك باستخدام الطلب السابق إلى الموقع <em>localhost:3001/persons/2</em>. وتذكر أنه لا تُرسل أية بيانات مع هذا الطلب.
</p>

<p>
	يمكنك استخدام الطلب HTTP-DELETE مع توابع المكتبة <a href="https://github.com/axios/axios" rel="external nofollow">axios</a> بنفس الطريقة التي استخدمناها فيها.
</p>

<p>
	<strong>انتبه</strong> لا يمكن اختيار "delete" كاسم لمتغيّر، لأنها كلمة محجوزة في JavaScript. فالشيفرة التالية مثلًا غير صحيحة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4984_78" style="">
<span class="com">// استخدم اسما آخر للمتغير</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">delete</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">id</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<h3>
	2.18 دليل الهاتف: الخطوة 10 *
</h3>

<p>
	أضف ميزة إلى تطبيقك تستبدل فيها الرقم القديم بالرقم الجديد إذا أضاف المستخدم رقمًا إلى شخص موجود مسبقًا. يفضل استخدام طلب HTTP-PUT لتنفيذ هذا الأمر. ليطلب تطبيقك من المستخدم أن يؤكد العملية إذا كانت معلومات الشخص موجودة مسبقًا.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/phonebook_step10_006.png.89d6a837214d055ca07473ff416d7a42.png" data-fileid="55267" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="55267" data-unique="64cup0s8t" src="https://academy.hsoub.com/uploads/monthly_2021_01/phonebook_step10_006.png.89d6a837214d055ca07473ff416d7a42.png" alt="phonebook_step10_006.png"></a>
</p>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://fullstackopen.com/en/part2/Altering_data_in_server" rel="external nofollow">Altering Data in Server</a> من سلسلة <a href="https://fullstackopen.com/en/" rel="external nofollow">Deep Dive Into Modern Web Development</a>
</p>
]]></description><guid isPermaLink="false">1097</guid><pubDate>Thu, 07 Jan 2021 13:00:00 +0000</pubDate></item><item><title>&#x625;&#x62D;&#x636;&#x627;&#x631; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; &#x645;&#x646; &#x627;&#x644;&#x62E;&#x627;&#x62F;&#x645; &#x641;&#x64A; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; React</title><link>https://academy.hsoub.com/programming/javascript/react/%D8%A5%D8%AD%D8%B6%D8%A7%D8%B1-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%85%D9%86-%D8%A7%D9%84%D8%AE%D8%A7%D8%AF%D9%85-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-react-r1096/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_01/p10-3.jpg.d2763855af02acd8d526ab4addadbadb.jpg" /></p>

<p>
	انصب تركيزنا حتى هذه اللحظة على كتابة الشيفرة للعمل مع الواجهة الأمامية (العمل من جهة المستخدم أو المتصفح)، وسنبدأ العمل على الواجهة الخلفية (جهة الخادم) عند الوصول إلى الفصل الثالث. مع ذلك سنخطو بداية خطواتنا بتعلم طريقة التواصل بين الشيفرة المكتوبة للمتصفح مع الخادم. سنستعمل عند تطويرنا التطبيقات أداة تدعى <a href="https://github.com/typicode/json-server" rel="external nofollow">JSON Server</a> لتأمين خادم افتراضي على جهازك. أنشئ ملفًا باسم db.json في المجلد الجذري للمشروع يحوي ما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7375_7" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="str">"notes"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
      </span><span class="str">"id"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"content"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"HTML is easy"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"date"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"2019-05-30T17:30:31.098Z"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"important"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
      </span><span class="str">"id"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"content"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Browser can execute only JavaScript"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"date"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"2019-05-30T18:39:34.091Z"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"important"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
      </span><span class="str">"id"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"content"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"GET and POST are the most important methods of HTTP protocol"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"date"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"2019-05-30T19:20:14.298Z"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"important"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">]</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يمكن <a href="https://github.com/typicode/json-server#getting-started" rel="external nofollow">تثبيت</a> كامل بيئة JSON على جهازك بتنفيذ الأمر <code>install -g json-server</code>. ويتطلب ذلك امتلاك امتيازات مدير النظام والخبرة بالتأكيد. لا يتطلب الأمر عادة تثبيتًا كاملًا، فيمكنك تثبيت ما يلزم في المجلد الجذري للمشروع بتنفيذ الأمر <code>npx json-server</code>:
</p>

<pre class="ipsCode">
npx json-server --port 3001 --watch db.json
</pre>

<p>
	يعمل JSON-server افتراضيًا على المنفذ 3000، ونظرًا لاستخدامنا create-react-app الذي يعمل أيضًا عند نفس المنفذ، لابد من تحديد منفذ جديد للخادم مثل 3001.
</p>

<p>
	توجه إلى العنوان <a href="http://localhost:3001/notes" ipsnoembed="false" rel="external nofollow">http://localhost:3001/notes</a> عبر متصفحك، ستلاحظ كيف سيعرض خادم JSON البيانات التي كتبناها سابقًا في ملف JSON.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/json_server_001.png.88e180ba03a5e952bc3e73c2071afecf.png" data-fileid="55259" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="55259" data-unique="m9cbj5jf3" src="https://academy.hsoub.com/uploads/monthly_2021_01/json_server_001.png.88e180ba03a5e952bc3e73c2071afecf.png" alt="json_server_001.png"></a>
</p>

<p>
	ثبت ملحقًا (plugin) إلى متصفحك لإظهار البيانات المكتوبة بصيغة JSON مثل <a href="https://chrome.google.com/webstore/detail/jsonview/chklaanhfefbnpoihckbnefhakgolnmc" rel="external nofollow">JSONView</a>، إن لم يتمكن من عرضها بشكل صحيح.
</p>

<p>
	لاحقًا، ستكون المهمة حفظ البيانات على الخادم. طبعًا خادم JSON في حالتنا. حيث تحضر شيفرة React الملاحظات ثم تصيّرها على الشاشة. وكذلك سترسل أية ملاحظات جديدة إلى الخادم لتجعلها "محفورة" في الذاكرة.
</p>

<p>
	يخزن خادم JSON البيانات في الملف db.json. في الواقع العملي، ستُخزَّن البيانات ضمن قواعد البيانات، لكن سيبقى هذا الخادم أداة مفيدة في متناول اليد لتجريب العمل مع الواجهة الخلفية خلال مرحلة التطوير دون عناء برمجة أي شيء عليه.
</p>

<p>
	سنتعلم المزيد حول مبادئ تطوير التطبيقات للتعامل مع الواجهة الخلفية بتفاصيل أكثر في <a href="https://fullstackopen.com/en/part3" rel="external nofollow">القسم 3</a>.
</p>

<h2>
	دور المتصفح كبيئة تشغيل
</h2>

<p>
	تقتضي مهمتنا الأولى إحضار الملاحظات الموجودة إلى تطبيقنا من العنوان <a href="http://localhost:3001/notes." ipsnoembed="false" rel="external nofollow">http://localhost:3001/notes.</a> ولقد تعلمنا بالفعل طريقةً لإحضار البيانات من الخادم باستخدام JavaScript في القسم 0. حيث استخدمنا <a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest" rel="external nofollow">XMLHttpRequest</a> في إحضار البيانات من الخادم وهو مايعرف بطلب HTTP باستخدام الكائن XHR. قُدّمت هذه التقنية عام 1999 وتدعمها حتى اللحظة جميع المتصفحات. لكن لا ينصح حاليًا باستخدام هذا الأسلوب، بل استخدام التابع <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-fetch-%D9%81%D9%8A-javascript-r739/" rel="">fetch</a> الذي تدعمه المتصفحات بشكل واسع. وتعتمد طريقة عمله على مايسمى <a href="https://wiki.hsoub.com/JavaScript/Promise/Using_promises" rel="external">وعودًا</a> promises، بدلًا من الأسلوب المقاد بالأحداث والذي يستخدمه XHR. كتذكرة من القسم 0 (لا يجب استخدام XHR إلا إن كنت بحاجة ماسة لذلك) سنحضر البيانات باستخدام هذا الأسلوب كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7375_9" style="">
<span class="kwd">const</span><span class="pln"> xhttp </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">XMLHttpRequest</span><span class="pun">()</span><span class="pln">

xhttp</span><span class="pun">.</span><span class="pln">onreadystatechange </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">readyState </span><span class="pun">==</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">status </span><span class="pun">==</span><span class="pln"> </span><span class="lit">200</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> data </span><span class="pun">=</span><span class="pln"> JSON</span><span class="pun">.</span><span class="pln">parse</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">responseText</span><span class="pun">)</span><span class="pln">
    </span><span class="com">// Data يعالج الاستجابة التي أسندت إلى المتغيّر</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

xhttp</span><span class="pun">.</span><span class="pln">open</span><span class="pun">(</span><span class="str">'GET'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'/data.json'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">)</span><span class="pln">
xhttp</span><span class="pun">.</span><span class="pln">send</span><span class="pun">()</span></pre>

<p>
	صرحنا في البداية عن معالج حدث للكائن <code>xhttp</code> الذي يمثل طلب HTML. يُستدعى هذا المعالج من قبل بيئة تشغيل JavaScript عندما تتغير حالة الكائن <code>xhttp</code>. ستُعالج طبعًا البيانات التي أُحضرت بشكل مناسب إذا تغيرت الحالة نتيجة لتلقي استجابة الخادم. ولهذا لا قيمة لأية شيفرة قد نضعها في معالج الحدث قبل إرسال الطلب إلى الخادم. لكن بالطبع سيتم تنفيذها في وقت لاحق. إذًا لا تُنفَّذ الشيفرة بشكل متزامن من الأعلى للأسفل، بل بشكل غير متزامن، وستستدعي JavaScript المعالج المصرح عنه سابقًا في مرحلة ما. تعبر البرمجة بالطريقة غير المتزامنة شائعة الاستخدام في Java، يوضح ذلك المثال التالي (انتبه إلى أن الشيفرة في المثال ليس شيفرة Java قابلة للتنفيذ):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7375_11" style="">
<span class="typ">HTTPRequest</span><span class="pln"> request </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">HTTPRequest</span><span class="pun">();</span><span class="pln">

</span><span class="typ">String</span><span class="pln"> url </span><span class="pun">=</span><span class="pln"> </span><span class="str">"https://fullstack-exampleapp.herokuapp.com/data.json"</span><span class="pun">;</span><span class="pln">
</span><span class="typ">List</span><span class="pun">&lt;</span><span class="typ">Note</span><span class="pun">&gt;</span><span class="pln"> notes </span><span class="pun">=</span><span class="pln"> request</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="pln">url</span><span class="pun">);</span><span class="pln">

notes</span><span class="pun">.</span><span class="pln">forEach</span><span class="pun">(</span><span class="pln">m </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">m</span><span class="pun">.</span><span class="pln">content</span><span class="pun">);</span><span class="pln">
</span><span class="pun">});</span></pre>

<p>
	ُتنفَّذ الشيفرة في Java سطرًا تلو الآخر وتتوقف بانتظار نتيجة طلب HTTP، أي إتمام تنفيذ الأمر <code>()request.get</code>. تُخزَّن بعدها البيانات التي يرسلها الخادم -وهي في حالتنا هذه "الملاحظات"- ليتم التعامل معها بالطريقة المطلوبة.
</p>

<p>
	تتبع بيئة تشغيل JavaScript أو محرك JavaScript بالمقابل <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop" rel="external nofollow">الأسلوب غير المتزامن</a>. ويتطلب ذلك من حيث المبدأ ألا تعيق عمليات الدخل والخرج <a href="https://en.wikipedia.org/wiki/Input/output" rel="external nofollow">IO-operations</a> عملية التنفيذ (مع بعض الاستثناءات). أي ينبغي أن تُستأنف عملية تنفيذ الشيفرة مباشرة بعد استدعاء دالة (الدخل/الخرج) دون انتظار الاستجابة. وعندما تكتمل العملية السابقة أو بالأحرى خلال مرحلة ما بعد اكتمالها، يستدعي محرك JavaScript معالج الحدث المعَّرف سابقًا.
</p>

<p>
	تعتبر محركات JavaScript حاليًا أحادية المسلك أو الخيط SingleThreaded، أي أنها لا تستطيع تنفيذ الشيفرات على التوازي. لذلك يفضل عمليًا اعتماد نموذج (دخل/خرج) لا يعيق تنفيذ الشيفرة، وإلا سيجمد المتصفح عند إحضار البيانات من الخادم على سبيل المثال. ومن التبعات الأخرى لاستخدام المسلك الأحادي للمحركات، هو توقف المتصفح عند تنفيذ شيفرات تستغرق وقتًا طويلًا خلال فترة التنفيذ.
</p>

<p>
	لو وضعنا الشيفرة التالية في أعلى التطبيق:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7375_13" style="">
<span class="pln">setTimeout</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'loop..'</span><span class="pun">)</span><span class="pln">
  let i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
  </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">50000000000</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    i</span><span class="pun">++</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'end'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">},</span><span class="pln"> </span><span class="lit">5000</span><span class="pun">)</span></pre>

<p>
	سيعمل التطبيق بشكل طبيعي لمدة خمس ثوان (وهو مُعامل الدالة <code>setTimeOut</code>) قبل أن يدخل في تنفيذ الحلقة الطويلة. حيث سيتوقف المتصفح عن العمل ولن نتمكن حتى من إغلاق المتصفح (على الأقل لا يمكننا ذلك في Chrome). وليبقى المتصفح متجاوبًا بشكل مستمر مع أفعال المستخدم وبسرعة كافية، لابد من اعتماد منطق لا يسمح بحسابات طويلة عند كتابة الشيفرة.
</p>

<p>
	ستجد على شبكة الإنترنت العديد من المواد المتعلقة بهذا الموضوع، ونخص بالذكر منها الملاحظات المفتاحية التي قدمها فيليب روبرتس بعنوان <a href="https://www.youtube.com/watch?v=8aGhZQkoFbQ" rel="external nofollow">What the heck is the event loop anyway</a> والتي تمثل عرضًا واضحًا للموضوع.
</p>

<p>
	يمكن تنفيذ الشيفرة على التوازي في المتصفحات الحديثة باستخدام ما يسمى عمال الويب <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers" rel="external nofollow">web workers</a>. لكن تنفيذ حلقة الأحداث في كل نافذة على حدى سيبقى بأسلوب <a href="https://medium.com/techtrument/multithreading-javascript-46156179cf9a" rel="external nofollow">المسلك الأحادي</a>
</p>

<h2>
	npm (مدير الحزم في Node.js)
</h2>

<p>
	لنعد إلى إحضار البيانات من الخادم. يمكن أن نستخدم -كما أشرنا سابقًا- الدالة <code>fetch</code> التي تعتمد على مفهوم الوعود. وتعتبر هذه الدالة من الأدوات المميزة والمعيارية التي تدعمها كل المتصفحات الحديثة. لكننا مع ذلك سنستخدم دوال المكتبة <a href="https://github.com/axios/axios" rel="external nofollow">axios</a> بدلًا منها للتواصل بين المتصفح والخادم. حيث تعمل دوال هذه المكتبة بشكل مشابه للدالة <code>fetch</code> لكن التعامل معها أسهل. والسبب المهم الآخر هو تعلم إضافة مكتبات خارجية والمعروفة باسم حزم npm ضمن مشاريع React.
</p>

<p>
	تُعرّف حاليًا كل مشاريع JavaScript باستخدام <a href="https://docs.npmjs.com/getting-started/what-is-npm" rel="external nofollow">npm</a>، وكذلك تطبيقات React المبنية باستخدام create-react-app. ويشير وجود الملف package.json في المجلد الجذري للمشروع على استخدام npm.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7375_15" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="str">"name"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"notes"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"version"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"0.1.0"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"private"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"dependencies"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"@testing-library/jest-dom"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"^4.2.4"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"@testing-library/react"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"^9.4.0"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"@testing-library/user-event"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"^7.2.1"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"react"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"^16.12.0"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"react-dom"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"^16.12.0"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"react-scripts"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"3.3.0"</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="str">"scripts"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"start"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"react-scripts start"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"build"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"react-scripts build"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"test"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"react-scripts test"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"eject"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"react-scripts eject"</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="str">"eslintConfig"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"extends"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"react-app"</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="str">"browserslist"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"production"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
      </span><span class="str">"&gt;0.2%"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"not dead"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"not op_mini all"</span><span class="pln">
    </span><span class="pun">],</span><span class="pln">
    </span><span class="str">"development"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
      </span><span class="str">"last 1 chrome version"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"last 1 firefox version"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"last 1 safari version"</span><span class="pln">
    </span><span class="pun">]</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	نشير هنا إلى الجزء الأهم من الملف package.json وهو ملفات الارتباط dependencies أو المكتبات الخارجية التي يعتمدها المشروع.
</p>

<p>
	سنبدأ الآن باستخدام axios. يمكننا تعريف هذه المكتبة مباشرة في الملف package.jaon، لكن من الأفضل أن نثبتها باستخدام الأمر:
</p>

<pre class="ipsCode">
npm install axios --save
</pre>

<p>
	<strong>ملاحظة</strong>: تنفذ جميع أوامر npm في المجلد الجذري للمشروع، وهو المكان الذي تجد فيه الملف package.jsons.
</p>

<p>
	بعد تثبيتها ستظهر axios ضمن ملفات الارتباط:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7375_17" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="str">"dependencies"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"@testing-library/jest-dom"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"^4.2.4"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"@testing-library/react"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"^9.4.0"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"@testing-library/user-event"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"^7.2.1"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"axios"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"^0.19.2"</span><span class="pun">,</span><span class="pln">    </span><span class="str">"react"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"^16.12.0"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"react-dom"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"^16.12.0"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"react-scripts"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"3.3.0"</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سُينزِّل أمر التثبيت السابق بالإضافة إلى المكتبة axios شيفرة المكتبة. وكغيرها من المكتبات ستجد شيفراتها ضمن المجلد node<em>modules الموجود في المجلد الجذري للمشروع. يمكنك أن تلاحظ ان المجلد node</em>modules يضم كميةً لا بأس بها من الأشياء المهمة.
</p>

<p>
	لنضف أمرًا آخر. ثبت json-server كملف ارتباط (وهذا فقط أثناء التطوير) باستخدام الأمر:
</p>

<pre class="ipsCode">
npm install json-server --save-dev
</pre>

<p>
	ثم عدّل قليلًا القسم Scripts من الملف package.json كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7375_19" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="com">// ... </span><span class="pln">
  </span><span class="str">"scripts"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"start"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"react-scripts start"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"build"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"react-scripts build"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"test"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"react-scripts test"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"eject"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"react-scripts eject"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"server"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"json-server -p3001 --watch db.json"</span><span class="pln">  
     </span><span class="pun">},</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يمكننا الآن تشغيل خادم json -وبلا تعريف لأية مُعاملات جديدة- من المجلد الجذري للمشروع باستخدام الأمر:
</p>

<pre class="ipsCode">
npm run server
</pre>

<p>
	سنطلع أكثر على الأداة npm في <a href="https://fullstackopen.com/en/part3" rel="external nofollow">القسم الثالث من منهاجنا</a>.
</p>

<p>
	<strong>ملاحظة</strong>: يجب إيقاف الخادم الذي شغلناه باستخدام الأمر السابق قبل تشغيل خادم جديد وإلا ستنتظرك المشاكل:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/jason_server_error_002.png.fca073eeee778da399128362eb8d277b.png" data-fileid="55258" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="55258" data-unique="6mjcrkuze" src="https://academy.hsoub.com/uploads/monthly_2021_01/jason_server_error_002.png.fca073eeee778da399128362eb8d277b.png" alt="jason_server_error_002.png"></a>
</p>

<p>
	تخبرنا رسالة الخطأ المطبوعة باللون الآخر عن المشكلة التالية:
</p>

<p>
	<em>لا يمكن الارتباط بالمنفذ 3001. اختر رجاء رقمًا آخر للمنفذ من خلال التعليمة <code>port--</code> أو من خلال ملف التهيئة لخادم json.</em>
</p>

<p>
	والسبب أن المنفذ 3001 قد شُغِل من قبل الخادم الذي أنشئ أولًا ولم يتم إيقافه، وبالتالي لم يستطع التطبيق الارتباط بهذا المنفذ.
</p>

<p>
	لاحظ أن هناك فرقًا بسيطًا بين أمري التثبيت التاليين:
</p>

<pre class="ipsCode">
npm install axios --save
npm install json-server --save-dev
</pre>

<p>
	ثُبِّتت المكتبة axios كملف ارتباط (save--) للتطبيق، لأن تنفيذه يتطلب وجود هذه المكتبة. بالمقابل ثُبِّت خادم jason كملف ارتباط للتطوير (save-dev--) لأن البرنامج لا يحتاجه فعلًا حتى يُنفّذ، بل سيساعد فقط خلال عملية تطوير التطبيق. سنتحدث أكثر عن موضوع ملفات الارتباط في القسم التالي.
</p>

<h2>
	مكتبة Axios والوعود
</h2>

<p>
	نحن الآن مستعدين للعمل مع axios، وسنفترض أن خادم json يعمل على المنفذ 3001.
</p>

<p>
	<strong>ملاحظة</strong>: لتشغل كل من jason و create-react-ap معًا عليك أن تفتح نافذتين من الطرفية node.js، كل نافذة لبرنامج.
</p>

<p>
	يمكن إدراج المكتبة ضمن التطبيق بالطريقة التي أدرجت فيها React وهي استعمال العبارة <code>import</code>. أضف مايلي إلى الملف index.js:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7375_21" style="">
<span class="kwd">import</span><span class="pln"> axios from </span><span class="str">'axios'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> promise </span><span class="pun">=</span><span class="pln"> axios</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'http://localhost:3001/notes'</span><span class="pun">)</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">promise</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> promise2 </span><span class="pun">=</span><span class="pln"> axios</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'http://localhost:3001/foobar'</span><span class="pun">)</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">promise2</span><span class="pun">)</span></pre>

<p>
	من المفترض أن يطبع ما يلي على الشاشة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/axios_promise_003.png.5438733f0322063f8f42f9ad8686bc25.png" data-fileid="55251" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="55251" data-unique="tbix9bnlt" src="https://academy.hsoub.com/uploads/monthly_2021_01/axios_promise_003.png.5438733f0322063f8f42f9ad8686bc25.png" alt="axios_promise_003.png"></a>
</p>

<p>
	يعيد التابع <code>get</code> وعدًا. ستجد في التوثيق على موقع موسوعة حسوب حول موضوع الوعود مايلي:
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p>
		يُعرّف الكائن Promise أو «الوعد» على أنّه كائنُ يمثّلُ النّتيجة النّهائيّة من إكمالٍ أو فشلٍ لعمليّةٍ غير متزامنة.
	</p>
</blockquote>

<p>
	وبكلمات أخرى، هو كائن يمثل عملية غير متزامنة يمكن أن يأخذ إحدى الحالات الثلاث التالية:
</p>

<ol>
<li>
		الوعد طور التنفيذ (pending): أي أن القيمة النهائية (والتي تمثلها إحدى الحالتين التاليتين) غير جاهزة حتى اللحظة.
	</li>
	<li>
		الوعد قد تحقق (fulfilled): إي أن العملية قد اكتملت والقيمة النهائية جاهزة. ويعني هذا عمومًا أن العملية قد نجحت. وقد يشار إلى هذه الحالة أحيانًا على أنها منجزة Resolved.
	</li>
	<li>
		الوعد قد رفض (rejected): أي أن خطأً قد منع تحديد القيمة النهائية. ويعني هذا عمومًا إخفاق العملية.
	</li>
</ol>
<p>
	تَحقَّق الوعد الأول في مثالنا السابق، ويمثل نجاح الطلب <code>(axios.get(http://localhost:3001/notes</code>، بينما رفض الوعد الثاني. وتُبلغنا الطرفية سبب الرفض بأنها تبدو كمحاولة لإرسال طلب HTTP-GET إلى عنوان غير موجود.
</p>

<p>
	إذا أردنا أن نعرف كيف وأين سنحصل على نتيجة العملية التي يمثلها الوعد، لابد من التصريح عن معالج حدث لهذا الوعد. ويتم ذلك باستخدام تابع axios يدعى <code>then</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7375_23" style="">
<span class="kwd">const</span><span class="pln"> promise </span><span class="pun">=</span><span class="pln"> axios</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'http://localhost:3001/notes'</span><span class="pun">)</span><span class="pln">

promise</span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">response</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	ستظهر على شاشة الطرفية المعلومات التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/using_axios_then_004.png.39ac9fbb51bf1b5e854907be6a77f5ac.png" data-fileid="55260" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="55260" data-unique="vzcmmjsih" src="https://academy.hsoub.com/uploads/monthly_2021_01/using_axios_then_004.png.39ac9fbb51bf1b5e854907be6a77f5ac.png" alt="using_axios_then_004.png"></a>
</p>

<p>
	تستدعي بيئة تشغيل JavaScript الدالة المصرح عنها داخل <code>then</code> وتمرر إليها الكائن <code>response</code> كمُعامل. يحوي المُعامل <code>response</code> كل البيانات الأساسية المتعلقة باستجابة الخادم على طلب HTTP-GET، وهي البيانات المعادة ورمز الحالة والترويسات. لا داعٍ لإسناد كائن الوعد إلى متغير، بل تُستخدم عادة طريقة الاستدعاء المتسلسل للتوابع كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7375_25" style="">
<span class="pln">axios</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'http://localhost:3001/notes'</span><span class="pun">).</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> notes </span><span class="pun">=</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	حيث تستخلص دالة الاستدعاء البيانات من الاستجابة التي تحصل عليها، ومن ثم تحفظها في متغير وتطبعها على شاشة الطرفية. ومن المفضل كتابة توابع الاستدعاء المتسلسل بحيث يقع كل تابع في سطر جديد وذلك لتسهيل قراءة الشيفرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7375_27" style="">
<span class="pln">axios
  </span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'http://localhost:3001/notes'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> notes </span><span class="pun">=</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">})</span></pre>

<p>
	يعيد الخادم البيانات المطلوبة على شكل سلسلة نصية طويلة غير منسقة بعد. ثم تحول axios البيانات إلى مصفوفة JavaScript لأن الخادم قد حدد نمط البيانات المرسلة على أنها application/json بنمط محارف utf-8 وذلك ضمن ترويسة نوع المحتوى content-type. وبهذا سنصبح قادرين أخيرًا على استخدام البيانات القادمة من الخادم.
</p>

<p>
	سنحاول الآن طلب الملاحظات من الخادم المحلي ثم تصييرها على شكل مكوِّن <code>App</code>. لكن تذكر أن هذه المقاربة ستعرضك لمشاكل عدة لأننا سنصيّر المكوِّن <code>App</code> عندما يستجيب الخادم فقط:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7375_29" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">ReactDOM</span><span class="pln"> from </span><span class="str">'react-dom'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> from </span><span class="str">'./App'</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> axios from </span><span class="str">'axios'</span><span class="pln">
axios</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'http://localhost:3001/notes'</span><span class="pun">).</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> notes </span><span class="pun">=</span><span class="pln"> response</span><span class="pun">.</span><span class="pln">data
  </span><span class="typ">ReactDOM</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">App</span><span class="pln"> notes</span><span class="pun">={</span><span class="pln">notes</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;,</span><span class="pln">
    document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'root'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	يمكن أن نستخدم الطريقة السابقة في ظروف معينة، لكنها سبب للعديد من المشاكل. لنحاول بدلًا من ذلك أن نضع أمر إحضار البيانات داخل المكوِّن<code>App</code> بدلًا من أن يكون جزءًا من دالة الاستجابة. لكن ما ليس واضحًا تمامًا هو المكان الذي سنضع فيه الأمر داخل المكوِّن.
</p>

<h2>
	خطافات التأثير
</h2>

<p>
	تعرفنا سابقًا على <a href="https://wiki.hsoub.com/React/hooks_state" rel="external">خطافات الحالة</a> التي ظهرت مع الإصدار <a href="https://www.npmjs.com/package/react/v/16.8.0" rel="external nofollow">16.8.0</a> من React، والتي تمنح دالة المكوِّن إمكانية تحديد حالته الراهنة. كما ظهرت في نفس النسخة خطافات التأثير <a href="https://wiki.hsoub.com/React/hooks_effect" rel="external">effect hooks</a> كميزة جديدة، وقد وثّقت كالتالي:
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p>
		تزودك خطافات التأثير بالقدرة على إنجاز تأثيرات جانبية في المكوِّنات المكتوبة على شكل دوال. ونذكر على سبيل المثال إحضار البيانات وإعداد الاشتراكات وتغيير DOM يدويًا في مكوِّنات React، كأمثلة عن التأثيرات الجانبية.
	</p>
</blockquote>

<p>
	إذًا فخطافات التأثير هو ما نحتاجه تمامًا لإحضار البيانات من الخادم. لنحذف أمر إحضار البيانات من ملف index.js، ولن نحتاج أيضًا إلى استخدام الخصائص لتمرير الملاحظات إلى المكوِّن، طالما أننا سنحضرها مباشرة من الخادم. وبالتالي سيبدو الملف index.js كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7375_31" style="">
<span class="typ">ReactDOM</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(&lt;</span><span class="typ">App</span><span class="pln"> </span><span class="pun">/&gt;,</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'root'</span><span class="pun">))</span></pre>

<p>
	سيتغير المكوِّن <code>App</code> ليصبح كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7375_34" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> useState</span><span class="pun">,</span><span class="pln"> useEffect </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> axios from </span><span class="str">'axios'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Note</span><span class="pln"> from </span><span class="str">'./components/Note'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">notes</span><span class="pun">,</span><span class="pln"> setNotes</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">([])</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">newNote</span><span class="pun">,</span><span class="pln"> setNewNote</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">showAll</span><span class="pun">,</span><span class="pln"> setShowAll</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln">

  useEffect</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
      console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'effect'</span><span class="pun">)</span><span class="pln">    
      axio</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'http://localhost:3001/notes'</span><span class="pun">).</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'promise fulfilled'</span><span class="pun">)</span><span class="pln">        
          setNotes</span><span class="pun">(</span><span class="pln">response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
      </span><span class="pun">})</span><span class="pln">  </span><span class="pun">},</span><span class="pln"> </span><span class="pun">[])</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'render'</span><span class="pun">,</span><span class="pln"> notes</span><span class="pun">.</span><span class="pln">length</span><span class="pun">,</span><span class="pln"> </span><span class="str">'notes'</span><span class="pun">)</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	كما أضفنا عدة أوامر للطباعة على الطرفية بغية توضيح مسار العملية، وستظهر عند التنفيذ كالتالي:
</p>

<pre class="ipsCode" id="ips_uid_7375_36">
render 0 notes
effect
promise fulfilled
render 3 notes
</pre>

<p>
	تنفذ في البداية الشيفرة الموجودة داخل جسم دالة المكوِّن، وتصيَّر النتيجة للمرة الأولى. وعندها ستُطبع العبارة <em>render 0 notes</em> على الطرفية إشارة إلى أن البيانات لم تحضر بعد من الخادم. ستُنفَّذ الدالة أو (التأثير) التالي مباشرة بعد أول عملية تصيير:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7375_38" style="">
<span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'effect'</span><span class="pun">)</span><span class="pln">
  axios
    </span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'http://localhost:3001/notes'</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'promise fulfilled'</span><span class="pun">)</span><span class="pln">
      setNotes</span><span class="pun">(</span><span class="pln">response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يؤدي تنفيذ التأثير السابق إلى طباعة العبارة <em>effect</em> على الطرفية، ويهيئ الأمر <code>axios.get</code> لعملية إحضار البيانات من الخادم ويُعرِّف في نفس الوقت معالج الحدث التالي للعملية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7375_40" style="">
<span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'promise fulfilled'</span><span class="pun">)</span><span class="pln">
  setNotes</span><span class="pun">(</span><span class="pln">response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	بمجرد وصول البيانات من الخادم، تستدعي بيئة تشغيل JavaScript معالج الحدث المرتبط بالعملية والذي يطبع بدوره العبارة <em>fulfilled</em> على الطرفية، ويخزّن الملاحظات القادمة من الخادم ضمن حالة المكوِّن باستخدام الدالة <code>(setNote(response.data</code>. وكما هو الحال دائمًا ستسبب تحديث حالة التطبيق إعادة تصيير المكوِّن، وستظهر ثلاث ملاحظات على الطرفية ومن ثم ستصيّر من جديد على الشاشة. لنلقي في النهاية نظرة شاملة على خطاف التأثير الذي استخدمناه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7375_42" style="">
<span class="pln">useEffect</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'effect'</span><span class="pun">)</span><span class="pln">
  axios
    </span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'http://localhost:3001/notes'</span><span class="pun">).</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'promise fulfilled'</span><span class="pun">)</span><span class="pln">
      setNotes</span><span class="pun">(</span><span class="pln">response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
</span><span class="pun">},</span><span class="pln"> </span><span class="pun">[])</span></pre>

<p>
	لنُعِد كتابة الشيفرة بشكل مختلف قليلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7375_44" style="">
<span class="kwd">const</span><span class="pln"> hook </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'effect'</span><span class="pun">)</span><span class="pln">
  axios
    </span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'http://localhost:3001/notes'</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'promise fulfilled'</span><span class="pun">)</span><span class="pln">
      setNotes</span><span class="pun">(</span><span class="pln">response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

useEffect</span><span class="pun">(</span><span class="pln">hook</span><span class="pun">,</span><span class="pln"> </span><span class="pun">[])</span></pre>

<p>
	سنرى الآن بوضوح أن الدالة <a href="https://wiki.hsoub.com/React/hooks_reference#useEffect" rel="external">useEffect</a> تأخذ في الواقع مُعاملين اثنين. الأول هو الدالة <em>effect</em> وتمثل التأثير ذاته وفقًا للتوثيق:
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p>
		تُنفَّذ الدالة effect افتراضيًا عند إتمام كل تصيير، لكن بالإمكان استدعاؤها عندما تتغير قيم معينة.
	</p>
</blockquote>

<p>
	يتم تنفيذ دالة التأثير افتراضيًا بعد أن يتم تصيير المكوِّن. لكننا نريد في حالتنا هذه أن ينفّذ فقط مع أول تصيير.
</p>

<p>
	أما المُعامل الثاني فيستخدم لتحديد <a href="https://wiki.hsoub.com/React/hooks_reference#.D8.AA.D9.86.D9.81.D9.8A.D8.B0_.D8.AA.D8.A3.D8.AB.D9.8A.D8.B1_.D8.B4.D8.B1.D8.B7.D9.8A.D9.8B.D9.91.D8.A7" rel="external">كم مرة سيُنفَّذ التأثير الجانبي</a>. فإذا وضعنا مصفوفة فارغة [ ] كقيمة له فإن التأثير سينفذ مرة واحدة عند أول تصيير للمكوِّن. يمكن أن نستخدم خطافات التأثير في أمور عدة بعد إحضار البيانات من الخادم، لكننا سنكتفي حاليًا بهذا الاستخدام.
</p>

<p>
	عليك أن تفكر مليًا بتسلسل الأحداث التي ناقشناها. أي جزء من الشيفرة نُفِّذ أولًا، وبأي ترتيب، وكم مرة، لأن فهم ترتيب الأحداث أمر حيوي جدًا. لاحظ أنه كان بالإمكان كتابة شيفرة دالة التأثير على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7375_46" style="">
<span class="pln">useEffect</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'effect'</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> eventHandler </span><span class="pun">=</span><span class="pln"> response </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'promise fulfilled'</span><span class="pun">)</span><span class="pln">
    setNotes</span><span class="pun">(</span><span class="pln">response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> promise </span><span class="pun">=</span><span class="pln"> axios</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'http://localhost:3001/notes'</span><span class="pun">)</span><span class="pln">
  promise</span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">eventHandler</span><span class="pun">)</span><span class="pln">
</span><span class="pun">},</span><span class="pln"> </span><span class="pun">[])</span></pre>

<p>
	أُسند مرجعٌ لدالة معالج الحدث إلى المتغيّر<code>eventHandler</code>. وخُزّن الوعد الذي يعيده التابع <code>get</code> في المتغيّر <code>promise</code>. يعرّف الاستدعاء (إعادة النداء) بجعل المتغير <code>eventHandler</code> كمُعامل للتابع <code>then</code> العائد إلى الوعد. فمن الضروري إسناد الدوال والوعود إلى متغيرات، ويفضل كتابة الأشياء بشكل مختصر:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7375_48" style="">
<span class="pln">useEffect</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'effect'</span><span class="pun">)</span><span class="pln">
  axios
    </span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'http://localhost:3001/notes'</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">.</span><span class="pln">then</span><span class="pun">(</span><span class="pln">response </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'promise fulfilled'</span><span class="pun">)</span><span class="pln">
      setNotes</span><span class="pun">(</span><span class="pln">response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
</span><span class="pun">},</span><span class="pln"> </span><span class="pun">[])</span></pre>

<p>
	تبقى لدينا مشكلة في التطبيق، فالملاحظات الجديدة التي ننشئها لن تخزن على الخادم. ستجد نسخة عن التطبيق حتى هذه المرحلة على <a href="https://github.com/fullstack-hy2020/part2-notes/tree/part2-4" rel="external nofollow">github</a> في الفرع part2-4.
</p>

<h2>
	بيئة التشغيل الخاصة بالتطوير
</h2>

<p>
	ستغدو تهيئة التطبيق بشكل كامل أصعب شيئًا فشيئًا. لنراجع إذًا ما الذي يحدث وأين سيحدث.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/dev_scheme_005.png.415c34c5bd6bbda793f58adf0d98fd84.png" data-fileid="55257" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="55257" data-unique="daib77dgx" src="https://academy.hsoub.com/uploads/monthly_2021_01/dev_scheme_005.png.415c34c5bd6bbda793f58adf0d98fd84.png" alt="dev_scheme_005.png"></a>
</p>

<p>
	تُنفَّذ شيفرة JavaScript التي توصّف التطبيق على المتصفح. حيث يحضر المتصفح هذه الشيفرة من خادم تطوير React. وهذا الأخير عبارة عن تطبيق يعمل مباشرة بعد تنفيذ الأمر <code>npm start</code>. يحول خادم التطوير dev-server شيفرة JavaScript إلى صيغة يفهمها المتصفح، كما يقوم بعدة أشياء أخرى منها تجميع شيفرة JavaScript من عدة ملفات في ملف واحد. سنطّلع على تفاصيل أكثر حول خادم التطوير في القسم 7.
</p>

<p>
	يحضر تطبيق React -الذي يعمل على المتصفح- البيانات بصيغة JSON من خادم JSON الذي يَشغُل المنفذ 3001 من جهازك. يحصل خادم JSON بدوره على البيانات المطلوبة من الملف db.json.
</p>

<p>
	تتواجد كل أقسام التطبيق حتى هذه المرحلة من مراحل التطوير ضمن آلة تطوير البرنامج Software Developer 's Machine. والتي تُعرف بالخادم المحلي. سيتغير الوضع حالما تنشر التطبيق على الإنترنت، وهذا ما سنراه في القسم 3.
</p>

<h2>
	التمارين 2.11 -2.14
</h2>

<h3>
	2.11 دليل الهاتف: الخطوة 6
</h3>

<p>
	خزن المعلومات الأولية للتطبيق في الملف db.json وضعه في المجلد الجذري للمشروع:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7375_50" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="str">"persons"</span><span class="pun">:[</span><span class="pln">
    </span><span class="pun">{</span><span class="pln"> 
      </span><span class="str">"name"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Arto Hellas"</span><span class="pun">,</span><span class="pln"> 
      </span><span class="str">"number"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"040-123456"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"id"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="pln"> 
      </span><span class="str">"name"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Ada Lovelace"</span><span class="pun">,</span><span class="pln"> 
      </span><span class="str">"number"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"39-44-5323523"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"id"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="pln"> 
      </span><span class="str">"name"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Dan Abramov"</span><span class="pun">,</span><span class="pln"> 
      </span><span class="str">"number"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"12-43-234345"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"id"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="pln"> 
      </span><span class="str">"name"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Mary Poppendieck"</span><span class="pun">,</span><span class="pln"> 
      </span><span class="str">"number"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"39-23-6423122"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"id"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">]</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	شغل خادم JSON على المنفذ 3001 وتأكد من أن الخادم سيعيد إليك قائمة الأشخاص السابقة عند طلب العنوان <a href="http://localhost:3001/persons" ipsnoembed="false" rel="external nofollow">http://localhost:3001/persons</a> من المتصفح. إن تلقيت رسالة الخطأ التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7375_52" style="">
<span class="pln">events</span><span class="pun">.</span><span class="pln">js</span><span class="pun">:</span><span class="lit">182</span><span class="pln">
      </span><span class="kwd">throw</span><span class="pln"> er</span><span class="pun">;</span><span class="pln"> </span><span class="com">// Unhandled 'error' event</span><span class="pln">
      </span><span class="pun">^</span><span class="pln">

</span><span class="typ">Error</span><span class="pun">:</span><span class="pln"> listen EADDRINUSE </span><span class="lit">0.0</span><span class="pun">.</span><span class="lit">0.0</span><span class="pun">:</span><span class="lit">3001</span><span class="pln">
    at </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">_errnoException </span><span class="pun">(</span><span class="pln">util</span><span class="pun">.</span><span class="pln">js</span><span class="pun">:</span><span class="lit">1019</span><span class="pun">:</span><span class="lit">11</span><span class="pun">)</span><span class="pln">
    at _exceptionWithHostPort </span><span class="pun">(</span><span class="pln">util</span><span class="pun">.</span><span class="pln">js</span><span class="pun">:</span><span class="lit">1041</span><span class="pun">:</span><span class="lit">20</span><span class="pun">)</span></pre>

<p>
	سيعني ذلك بأن المنفذ 3001 محجوز من قبل تطبيقٍ آخر كخادم JSON آخر. أغلق كل التطبيقات الأخرى أو غيّر رقم المنفذ. عدّل التطبيق ليحضر لك بيانات الأشخاص من الخادم باستخدام المكتبة axios. ثم أكمل عملية إحضار البيانات باستخدام <a href="https://wiki.hsoub.com/React/hooks_effect" rel="external">خطاف التأثير</a>.
</p>

<h3>
	2.12 معلومات عن البلدان: الخطوة 1 *
</h3>

<p>
	تزودك الواجهة البرمجية <a href="https://restcountries.eu/" rel="external nofollow">https://restcountries.eu</a> بمعلومات عن بلدان مختلفة بصيغة تفهمها آلة التطوير، والتي تدعى REST <abbr title="Application Programming Interface | واجهة برمجية">API</abbr>.
</p>

<p>
	أنشئ تطبيقًا يمكننا من خلاله الاطلاع على معلوماتٍ من بعض الدول. من المفترض أن يحصل تطبيقك على البيانات من نقطة الاتصال <a href="https://restcountries.eu/#api-endpoints-all" rel="external nofollow">all</a>.
</p>

<p>
	واجهة المستخدم بسيطة جدًا، فالبحث عن الدولة يكون بكتابة اسمها في حقل البحث. وإن ظهرت العديد من النتائج المطابقة للبحث (أكثر من 10) تظهر رسالة تنبيه للمستخدم أن يحدد بحثه بشكل أدق.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/country_data_step1_006.png.0105a990a3588b55c9ec7a7297ff2791.png" data-fileid="55252" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="55252" data-unique="uclmu6h2c" src="https://academy.hsoub.com/uploads/monthly_2021_01/country_data_step1_006.png.0105a990a3588b55c9ec7a7297ff2791.png" alt="country_data_step1_006.png"></a>
</p>

<p>
	وإن ظهرت عدة نتائج للبحث، لكنها أقل من 10 ستظهر جميع النتائج على الشاشة
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/country_data_step1_show_007.png.701fe18555cedea0bf5e49981502bca6.png" data-fileid="55253" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="55253" data-unique="xyxj6p3a2" src="https://academy.hsoub.com/uploads/monthly_2021_01/country_data_step1_show_007.png.701fe18555cedea0bf5e49981502bca6.png" alt="country_data_step1_show_007.png"></a>
</p>

<p>
	أما إن كانت نتيجة البحث دولة واحدة، ستظهر بعض المعلومات الأولية عنها مع علمها واللغات المحكية فيها.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/country_data_step1_show_one_008.png.a6605fc9f1d2bd687a6203e7a88f5393.png" data-fileid="55254" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="55254" data-unique="1sev6reyu" src="https://academy.hsoub.com/uploads/monthly_2021_01/country_data_step1_show_one_008.png.a6605fc9f1d2bd687a6203e7a88f5393.png" alt="country_data_step1_show_one_008.png"></a>
</p>

<p>
	<strong>ملاحظة</strong>: يكفي أن يعمل التطبيق لأغلبية بلدان العالم. لأن بعض الدول مثل السودان ستربك التطبيق كون كلمة السودان هي أيضًا جزء من اسم دولة أخرى هي جنوب السودان. لا تلق بالًا لهذا الموضوع الآن.
</p>

<p>
	<strong>تحذير</strong>: تنشئ الأداة create-react-app مستودع git محلي يحتوي المشروع، إلا إن كان في المجلد مستودع محلي سابق. من المرجح أنك لا تريد أن يغدو المشروع مستودعًا، لهذا نفذ الأمر التالي<code>rm -rf .git</code> في مسار المشروع.
</p>

<h3>
	2.13 معلومات عن البلدان: الخطوة 2 *
</h3>

<p>
	<strong>هناك الكثير من التمارين التي ينبغي إنجازها، لا تبقى طويلًا في هذا التمرين! (معلّم على أنه غير أساسي)</strong>
</p>

<p>
	حسِّن التطبيق بحيث يعرض زرًا بجانب الدول التي تظهر كنتيجة للبحث، يعطينا بالنقر عليه المعلومات التي ذكرناها سابقًا عن هذه الدولة.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/country_data_step2_show_multi_009.png.c65b5498595cb314413bae7992886959.png" data-fileid="55255" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="55255" data-unique="m9aor7vz1" src="https://academy.hsoub.com/uploads/monthly_2021_01/country_data_step2_show_multi_009.png.c65b5498595cb314413bae7992886959.png" alt="country_data_step2_show_multi_009.png"></a>
</p>

<p>
	يكفي هنا أيضًا أن يعمل التطبيق بالنسبة لأغلبية البلدان، تجاهل الحالة التي أشرنا إليها سابقًا.
</p>

<h3>
	2.14 معلومات عن البلدان: الخطوة 3 *
</h3>

<p>
	<strong>هناك الكثير من التمارين التي ينبغي إنجازها لا تبقى طويلًا في هذا التمرين! (معلّم على أنه غير أساسي)</strong>
</p>

<p>
	أضف إلى المعلومات التي تظهر عندما تكون نتيجة البحث دولة واحدة فقط، معلومات عن حالة الطقس في العاصمة. ستجد الكثير من الواجهات التي تزودك بأحوال الطقس مثل <a href="https://weatherstack.com." ipsnoembed="false" rel="external nofollow">https://weatherstack.com.</a>
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/country_data_step3_weather_010.png.68d2c2a1b0dee80bbc30e76fa096bf3d.png" data-fileid="55256" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="55256" data-unique="01soc9h5h" src="https://academy.hsoub.com/uploads/monthly_2021_01/country_data_step3_weather_010.png.68d2c2a1b0dee80bbc30e76fa096bf3d.png" alt="country_data_step3_weather_010.png"></a>
</p>

<p>
	<strong>ملاحظة</strong>: ستحتاج إلى مفتاح لأي واجهة برمجية لخدمات الطقس. لا تحتفظ بالمفتاح ضمن عنصر التحكم ولا تبقه كما هو ضمن الشيفرة المصدرية لتطبيقك. استخدم بدلًا من ذلك <a href="https://create-react-app.dev/docs/adding-custom-environment-variables/" rel="external nofollow">متغيرات البيئة</a> لحفظ المفتاح. فلو افترضنا أن مفتاح الواجهة هو <em>0p53cr3t4p1k3yv4lu3</em>، فعندما يُقلع التطبيق بالشكل التالي:
</p>

<pre class="ipsCode">
REACT_APP_API_KEY='t0p53cr3t4p1k3yv4lu3' npm start // لملف إقلاع لينوكس وماكنتوش
($env:REACT_APP_API_KEY='t0p53cr3t4p1k3yv4lu3') -and (npm start) // powershell ويندوز 
set REACT_APP_API_KEY='t0p53cr3t4p1k3yv4lu3' &amp;&amp; npm start // سطر أوامر ويندوز
</pre>

<p>
	يمكنك الوصول إلى قيمة المفتاح من خلال الكائن <code>process.env</code> كالتالي:
</p>

<pre class="ipsCode">
const api_key = process.env.REACT_APP_API_KEY
//يمتلك التطبيق الآن قيمة المفتاح الذي وضعناه عند الإقلاع 
</pre>

<p>
	<strong>انتبه</strong>: إن أنشأت التطبيق باستخدام الأمر <code>npx create-react-app</code> وأردت أن تطلق اسمًا آخر على متغيّر البيئة يجب أن يبدأ الاسم بالعبارة <code>_REACT_APP</code>. كما يمكنك إنشاء ملف لاحقته <code>env.</code> في المجلد الجذري للمشروع وتضع فيه الشيفرة التالية:
</p>

<pre class="ipsCode">
# .env
REACT_APP_API_KEY=t0p53cr3t4p1k3yv4lu3
</pre>

<p>
	بدلًا من تعريف المتغير من خلال سطر الأوامر command line كل مرة. <strong>انتبه</strong>: عليك إعادة تشغيل الخادم من جديد حتى تُطبّق التغييرات.
</p>

<p>
	ترجمة -وبتصرف- للفصل Getting Data from Server](https://fullstackopen.com/en/part2/getting<em>data</em>from_server) من سلسلة <a href="https://fullstackopen.com/en/" rel="external nofollow">Deep Dive Into Modern Web Development</a>
</p>
]]></description><guid isPermaLink="false">1096</guid><pubDate>Tue, 05 Jan 2021 13:00:00 +0000</pubDate></item><item><title>&#x625;&#x646;&#x634;&#x627;&#x621; &#x627;&#x644;&#x646;&#x645;&#x627;&#x630;&#x62C; (forms) &#x641;&#x64A; React</title><link>https://academy.hsoub.com/programming/javascript/react/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%A7%D9%84%D9%86%D9%85%D8%A7%D8%B0%D8%AC-forms-%D9%81%D9%8A-react-r1095/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_01/p9-2.jpg.9ca35e5c4ab17920f9e068f216f75cc8.jpg" /></p>

<p>
	سنوسّع تطبيقنا وذلك بالسماح للمستخدمين أن يضيفوا ملاحظات جديدة. من الأفضل هنا أن نخزّن الملاحظات داخل حالة التطبيق <code>App</code>، ذلك إن أردنا أن تحدثّ الصفحة محتوياتها عند إضافة الملاحظة الجديدة. لندرج إذًا الدالة <a href="https://wiki.hsoub.com/React/hooks_state" rel="external">useState</a> ونعرّف قطعًا للحالة تأخذ قيمها الابتدائية من القيم الابتدائية لمصفوفة الملاحظات التي يتم تمريرها كخصائص:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_147_7" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> useState </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react'</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Note</span><span class="pln"> from </span><span class="str">'./components/Note'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">notes</span><span class="pun">,</span><span class="pln"> setNotes</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="pln">props</span><span class="pun">.</span><span class="pln">notes</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Notes</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> 
          </span><span class="pun">&lt;</span><span class="typ">Note</span><span class="pln"> key</span><span class="pun">={</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}</span><span class="pln"> note</span><span class="pun">={</span><span class="pln">note</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">)}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span></pre>

<p>
	يستخدم المكوِّن الدالة <code>useState</code> لتهيئة قطع الحالة المخزنة في <code>notes</code> بمصفوفة الملاحظات التي تمرر كخصائص:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_147_9" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">notes</span><span class="pun">,</span><span class="pln"> setNotes</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="pln">props</span><span class="pun">.</span><span class="pln">notes</span><span class="pun">)</span><span class="pln"> 

  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	علينا استخدام مصفوفة فارغة لتهيئة الملاحظات إن أردنا أن نبدأ التطبيق بقائمة فارغة من الملاحظات. سنحذف أيضًا الخصائص <code>props</code> من تعريف الدالة طالما أنها لن تُستخدم:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_147_11" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">notes</span><span class="pun">,</span><span class="pln"> setNotes</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">([])</span><span class="pln"> 

  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span><span class="pln">  </span></pre>

<p>
	لنركز الآن على القيم الأولية التي تمرر كخصائص للدالة، حيث سنضيف <a href="https://wiki.hsoub.com/HTML#.D8.A7.D9.84.D9.86.D9.85.D8.A7.D8.B0.D8.AC" rel="external">نموذج</a> HTML إلى المكوِّن الذي سيضيف الملاحظات الجديدة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_147_13" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">notes</span><span class="pun">,</span><span class="pln"> setNotes</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="pln">props</span><span class="pun">.</span><span class="pln">notes</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> addNote </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'button clicked'</span><span class="pun">,</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Notes</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> 
          </span><span class="pun">&lt;</span><span class="typ">Note</span><span class="pln"> key</span><span class="pun">={</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}</span><span class="pln"> note</span><span class="pun">={</span><span class="pln">note</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">)}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">form onSubmit</span><span class="pun">={</span><span class="pln">addNote</span><span class="pun">}&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">input </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">button type</span><span class="pun">=</span><span class="str">"submit"</span><span class="pun">&gt;</span><span class="pln">save</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
       </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لقد أضفنا أيضًا الدالة <code>addNote</code> كمعالج حدث يُستدعى عندما يُسلّم (submit) النموذج عند النقر على زر التسليم. سنستخدم الطريقة التي ناقشناها في [القسم 1]() لتعريف معالج الحدث:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_147_15" style="">
<span class="kwd">const</span><span class="pln"> addNote </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'button clicked'</span><span class="pun">,</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يؤدي المعامل <code>event</code> دور <a href="https://wiki.hsoub.com/React/handling_events" rel="external">الحدث</a> الذي يستدعي دالة المعالج. يستدعي معالج الأحداث التابع <code>()event.preventDefaultr</code> الذي يمنع حدوث التسليم الافتراضي للنموذج، والذي يسبب إعادة تحميل الصفحة إضافة إلى عدة أشياء أخرى. لنطبع الآن وجهة الحدث <code>event.target</code> على الطرفية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/eveny_target_001.png.02bc652888e3129bffead66926400df9.png" data-fileid="55244" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="55244" data-unique="s8ph8hfpv" src="https://academy.hsoub.com/uploads/monthly_2021_01/eveny_target_001.png.02bc652888e3129bffead66926400df9.png" alt="eveny_target_001.png"></a>
</p>

<p>
	إنّ النموذج الذي عرّفناه في المكوًّن هو وجهة الحدث كما هو واضح، لكن كيف سنصل إلى البيانات الموجودة ضمن عنصر الإدخال <code>input</code> (وهو مربع النص في حالتنا) في النموذج؟ طرق كثيرة يمكن أن تفي بالغرض. سنلقي نظرة على أولها وهي استخدام <a href="https://wiki.hsoub.com/React/forms#.D8.A7.D9.84.D9.85.D9.83.D9.88.D9.86.D8.A7.D8.AA_.D8.A7.D9.84.D9.85.D8.B6.D8.A8.D9.88.D8.B7.D8.A9" rel="external">المكوِّنات المقادة</a> (controlled components). لنضف الآن قطعة حالة جديدة تدعى <code>newNote</code> لتخزّن ما يدخله المستخدم في العنصر <code>input</code> ضمن الصفة <code>value</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_147_17" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">notes</span><span class="pun">,</span><span class="pln"> setNotes</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="pln">props</span><span class="pun">.</span><span class="pln">notes</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">newNote</span><span class="pun">,</span><span class="pln"> setNewNote</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="pln">    </span><span class="str">'a new note...'</span><span class="pln">  </span><span class="pun">)</span><span class="pln"> 
  </span><span class="kwd">const</span><span class="pln"> addNote </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'button clicked'</span><span class="pun">,</span><span class="pln"> event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Notes</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> 
          </span><span class="pun">&lt;</span><span class="typ">Note</span><span class="pln"> key</span><span class="pun">={</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}</span><span class="pln"> note</span><span class="pun">={</span><span class="pln">note</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">)}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">form onSubmit</span><span class="pun">={</span><span class="pln">addNote</span><span class="pun">}&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">input value</span><span class="pun">={</span><span class="pln">newNote</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">button type</span><span class="pun">=</span><span class="str">"submit"</span><span class="pun">&gt;</span><span class="pln">save</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">   
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيُخزّن النص الموجود في مربع النص كقيمة ابتدائية للملاحظة الجديدة، لكن لو حاولنا إضافة أي نص فلن يسمح مربع النص بذلك. ستعرض الطرفية تنبيهًا قد يعطينا دليلًا على الخطأ الذي وقع:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/onchange_missing_warning_002.png.a1d74c816924164b23dedcadbf2b81f5.png" data-fileid="55245" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="55245" data-unique="k5m8cor4a" src="https://academy.hsoub.com/uploads/monthly_2021_01/onchange_missing_warning_002.png.a1d74c816924164b23dedcadbf2b81f5.png" alt="onchange_missing_warning_002.png"></a>
</p>

<p>
	طالما أننا أسندنا قطعة من حالة المكوِّن <code>App</code> إلى الصفة <code>value</code> لعنصر الإدخال، <a href="https://wiki.hsoub.com/React/forms#.D8.A7.D9.84.D9.85.D9.83.D9.88.D9.86.D8.A7.D8.AA_.D8.A7.D9.84.D9.85.D8.B6.D8.A8.D9.88.D8.B7.D8.A9" rel="external">فسيتحكم</a> المكوِّن الآن بسلوك هذا العنصر. لذا لابد من تعريف معالج حدث جديد يزامن التغييرات التي تحدث في عنصر الإدخال مع حالة المكوِّن إن أردنا الكتابة ضمنه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_147_19" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">notes</span><span class="pun">,</span><span class="pln"> setNotes</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="pln">props</span><span class="pun">.</span><span class="pln">notes</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">newNote</span><span class="pun">,</span><span class="pln"> setNewNote</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="pln">
    </span><span class="str">'a new note...'</span><span class="pln">
  </span><span class="pun">)</span><span class="pln"> 

  </span><span class="com">// ...</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> handleNoteChange </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">value</span><span class="pun">)</span><span class="pln">    setNewNote</span><span class="pun">(</span><span class="pln">event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">value</span><span class="pun">)</span><span class="pln">  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Notes</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> 
          </span><span class="pun">&lt;</span><span class="typ">Note</span><span class="pln"> key</span><span class="pun">={</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}</span><span class="pln"> note</span><span class="pun">={</span><span class="pln">note</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">)}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">form onSubmit</span><span class="pun">={</span><span class="pln">addNote</span><span class="pun">}&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">input
          value</span><span class="pun">={</span><span class="pln">newNote</span><span class="pun">}</span><span class="pln">
          onChange</span><span class="pun">={</span><span class="pln">handleNoteChange</span><span class="pun">}</span><span class="pln">        </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">button type</span><span class="pun">=</span><span class="str">"submit"</span><span class="pun">&gt;</span><span class="pln">save</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">   
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سنعرف الآن معالج حدث للخاصية <code>onChange</code> لعنصر إدخال النموذج:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_147_21" style="">
<span class="pun">&lt;</span><span class="pln">input
  value</span><span class="pun">={</span><span class="pln">newNote</span><span class="pun">}</span><span class="pln">
  onChange</span><span class="pun">={</span><span class="pln">handleNoteChange</span><span class="pun">}</span><span class="pln">
</span><span class="pun">/&gt;</span></pre>

<p>
	سيُستدعى الآن معالج الحدث عند حدوث أية تغييرات في عنصر الإدخال، وستتلقى دالة المعالج كائن الحدث كمعامل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_147_25" style="">
<span class="kwd">const</span><span class="pln"> handleNoteChange </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">value</span><span class="pun">)</span><span class="pln">
  setNewNote</span><span class="pun">(</span><span class="pln">event</span><span class="pun">.</span><span class="pln">target</span><span class="pun">.</span><span class="pln">value</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ترتبط الآن الخاصية <code>target</code> لكائن الحدث بعنصر الإدخال المُقاد (من قِبل المكوِّن)، وستشير القيمة <code>event.target.value</code> إلى محتوى عنصر الإدخال.
</p>

<p>
	<strong>ملاحظة</strong>: لا داعي لاستدعاء التابع <code>()event.preventDefault</code> كما فعلنا سابقًا، لعدم وجود عمليات افتراضية عند حدوث تغيرات على عنصر الإدخال.
</p>

<p>
	يمكنك تتبع ما يجري عند استدعاء المعالج ضمن النافذة console في الطرفية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/console_track_changes_003.png.b7ce0314ceb006061d5bc39852986c00.png" data-fileid="55243" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="55243" data-unique="8gtaxtldz" src="https://academy.hsoub.com/uploads/monthly_2021_01/console_track_changes_003.png.b7ce0314ceb006061d5bc39852986c00.png" alt="console_track_changes_003.png"></a>
</p>

<p>
	سترى كيف تتغير الحالة مباشرة داخل نافذة <a href="https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi" rel="external nofollow">React Devtools</a>، طبعًا إن كنت قد ثبتها سابقًا.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/react_dev_tools_004.png.9f7ba7d5e126b14ad1846e7fbab94b4b.png" data-fileid="55250" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="55250" data-unique="29v1fr61q" src="https://academy.hsoub.com/uploads/monthly_2021_01/react_dev_tools_004.png.9f7ba7d5e126b14ad1846e7fbab94b4b.png" alt="react_dev_tools_004.png"></a>
</p>

<p>
	ستعكس قطعة الحالة <code>newNote</code> في المكوِّن <code>App</code> التغيرات في قيمة عنصر الإدخال، إذًا يمكننا إكمال الدالة <code>addNote</code> التي تضيف ملاحظة جديدة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_147_27" style="">
<span class="kwd">const</span><span class="pln"> addNote </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  event</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">()</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> noteObject </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> newNote</span><span class="pun">,</span><span class="pln">
    date</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">().</span><span class="pln">toISOString</span><span class="pun">(),</span><span class="pln">
    important</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">random</span><span class="pun">()</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0.5</span><span class="pun">,</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> notes</span><span class="pun">.</span><span class="pln">length </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  setNotes</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">concat</span><span class="pun">(</span><span class="pln">noteObject</span><span class="pun">))</span><span class="pln">
  setNewNote</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سننشئ أولًا كائنًا جديدًا يدعى <code>noteObject</code> يتلقى محتواه من قيمة الحالة <code>newState</code>. بينما يتولّد المعرِّف الفريد <code>id</code> وفقًا لعدد الملاحظات. سينجح هذا الأسلوب في تطبيقنا طالما أنه لن يستخدم لحذف الملاحظات. سنعطي الملاحظة احتمالًا بنسبة 50% لأن تعتبر مهمة بالاستفادة من الدالة <code>()Math.random</code> وهي دالة تستخدم لتوليد أرقام عشوائية.
</p>

<p>
	نستخدم التابع <a href="https://wiki.hsoub.com/JavaScript/Array/concat" rel="external">concat</a> الذي تعرفنا عليه <a href="https://fullstackopen.com/en/part1/java_script#arrays" rel="external nofollow">سابقًا</a> في إضافة الملاحظة الجديدة إلى قائمة الملاحظات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_147_33" style="">
<span class="pln">setNotes</span><span class="pun">(</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">concat</span><span class="pun">(</span><span class="pln">noteObject</span><span class="pun">))</span></pre>

<p>
	لا يغير التابع المصفوفة الأصلية بل ينشئ مصفوفة جديدة وينسخ العناصر إليها ثم يضيف العنصر الجديد إلى نهايتها. وهذا أمر ضروري، إذ <a href="https://wiki.hsoub.com/React/state_and_lifecycle#.D8.A7.D8.B3.D8.AA.D8.AE.D8.AF.D8.A7.D9.85_.D8.A7.D9.84.D8.AD.D8.A7.D9.84.D8.A9_.D8.A8.D8.B4.D9.83.D9.84_.D8.B5.D8.AD.D9.8A.D8.AD" rel="external">لا يجب علينا تغيير الحالة بشكل مباشر</a> في React. سيقوم معالج الحدث أيضًا بتصفير قيمة عنصر الإدخال المقاد باستدعاء الدالة <code>setNewNote</code> المعرفة كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_147_35" style="">
<span class="pln">setNewNote</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span></pre>

<p>
	ستجد شيفرة التطبيق الذي نعمل عليه في المسار part2-2 <a href="https://github.com/fullstack-hy2020/part2-notes/tree/part2-2" rel="external nofollow">ضمن المخزن المخصص على github</a>.
</p>

<h2>
	انتقاء العناصر التي ستعرض
</h2>

<p>
	سنضيف مهمة جديدة للتطبيق تقتضي إظهار الملاحظات الهامة فقط. ولنبدأ بإضافة قطعة حالة جديدة للمكوِّن <code>App</code> مهمتها تحديد الملاحظات التي يجب أن تعرض:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_147_37" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">notes</span><span class="pun">,</span><span class="pln"> setNotes</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="pln">props</span><span class="pun">.</span><span class="pln">notes</span><span class="pun">)</span><span class="pln"> 
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">newNote</span><span class="pun">,</span><span class="pln"> setNewNote</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">showAll</span><span class="pun">,</span><span class="pln"> setShowAll</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln">  
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سنعدل المكوًن أيضًا لكي يخزن قائمة بكل الملاحظات التي ستعرض ضمن المتغيّر <code>notesDirectShow</code>. يعتمد اختيار عناصر القائمة على حالة المكوِّن:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_147_39" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> useState </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Note</span><span class="pln"> from </span><span class="str">'./components/Note'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">notes</span><span class="pun">,</span><span class="pln"> setNotes</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="pln">props</span><span class="pun">.</span><span class="pln">notes</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">newNote</span><span class="pun">,</span><span class="pln"> setNewNote</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln"> 
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">showAll</span><span class="pun">,</span><span class="pln"> setShowAll</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln">

  </span><span class="com">// ...</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> notesToShow </span><span class="pun">=</span><span class="pln"> showAll    
    </span><span class="pun">?</span><span class="pln"> notes    
    </span><span class="pun">:</span><span class="pln"> notes</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> note</span><span class="pun">.</span><span class="pln">important </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Notes</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">notesToShow</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Note</span><span class="pln"> key</span><span class="pun">={</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}</span><span class="pln"> note</span><span class="pun">={</span><span class="pln">note</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">)}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="com">// ...</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يظهر تعريف المتغيّر <code>notesDirectShow</code> مختصرًا بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_147_41" style="">
<span class="kwd">const</span><span class="pln"> notesToShow </span><span class="pun">=</span><span class="pln"> showAll
  </span><span class="pun">?</span><span class="pln"> notes
  </span><span class="pun">:</span><span class="pln"> notes</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> note</span><span class="pun">.</span><span class="pln">important </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">)</span></pre>

<p>
	سترى في التعريف <a href="https://wiki.hsoub.com/JavaScript/Conditional_Operator" rel="external">العامل الشرطي</a> الذي ستراه أيضًا في عدة لغات برمجة أخرى. وسنشرح منطق هذا العامل من خلال المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_147_43" style="">
<span class="kwd">const</span><span class="pln"> result </span><span class="pun">=</span><span class="pln"> condition </span><span class="pun">?</span><span class="pln"> val1 </span><span class="pun">:</span><span class="pln"> val2</span></pre>

<p>
	تعمل هذه الصيغة كالتالي: سيأخذ المتغير <code>result</code> القيمة <code>val1</code> إذا تحقق الشرط <code>condition</code> وإلا سيأخذ القيمة <code>val2</code>.
</p>

<p>
	وبالعودة إلى الصيغة الموجودة في شيفرة التطبيق، سيأخذ المتغيّر <code>notesToShow</code> القيمة <code>notes</code>، وستظهر كل الملاحظات، إذا كان الشرط <code>showAll</code> محققًا. وإلا سيأخذ القيمة الأخرى، وستظهر الملاحظات الهامة فقط.
</p>

<p>
	لاحظ أن عملية الانتقاء قد تمت بمساعدة تابع الانتقاء في المصفوفات <a href="https://wiki.hsoub.com/JavaScript/Array/filter" rel="external">filter</a>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_147_45" style="">
<span class="pln">notes</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> note</span><span class="pun">.</span><span class="pln">important </span><span class="pun">===</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">)</span></pre>

<p>
	ليس لعامل الموازنة (===) أهمية طالما أن القيمة <code>note.important</code> من النمط المنطقي. إذًا يمكننا ببساطة كتابة السطر البرمجي السابق بالشكل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_147_47" style="">
<span class="pln">notes</span><span class="pun">.</span><span class="pln">filter</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> note</span><span class="pun">.</span><span class="pln">important</span><span class="pun">)</span></pre>

<p>
	إن المغزى من كتابة عامل الموازنة بالشكل(===) هو توضيح ناحية هامة بأن العامل (==) لا يؤدي دوره بالشكل المطلوب في كل الحالات ويجب عدم استخدامه في المقارنة حصرًا. اقرأ <a href="https://academy.hsoub.com/pages/write-for-us/style-guide/" rel="">المزيد حول الموضوع</a> لفهمٍ أعمق. يمكنك اختبار انتقاء الملاحظات بجعل القيمة الأولية <code>false</code> لقطعة الحالة <code>showAll</code>.
</p>

<p>
	سنقوم تاليًا بمنح المستخدم إمكانية تغيير قيمة الحالة <code>showAll</code> من واجهة المستخدم. وستظهر الشيفرة بعد التعديل كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_147_49" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> useState </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln"> 
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Note</span><span class="pln"> from </span><span class="str">'./components/Note'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">notes</span><span class="pun">,</span><span class="pln"> setNotes</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="pln">props</span><span class="pun">.</span><span class="pln">notes</span><span class="pun">)</span><span class="pln"> 
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">newNote</span><span class="pun">,</span><span class="pln"> setNewNote</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">showAll</span><span class="pun">,</span><span class="pln"> setShowAll</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln">

  </span><span class="com">// ...</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Notes</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setShowAll</span><span class="pun">(!</span><span class="pln">showAll</span><span class="pun">)}&gt;</span><span class="pln">
          show </span><span class="pun">{</span><span class="pln">showAll </span><span class="pun">?</span><span class="pln"> </span><span class="str">'important'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">'all'</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">notesToShow</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Note</span><span class="pln"> key</span><span class="pun">={</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}</span><span class="pln"> note</span><span class="pun">={</span><span class="pln">note</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">)}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="com">// ...    </span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سنتحكم بإخفاء أو إظهار الملاحظات باستخدام زر، وسيكون معالج الحدث الخاص به بسيطًا بحيث يمكن تعريفه مباشرة داخل الصفة <code>onClick</code>. يبدّل معالج الحدث قيمة <code>showAll</code> عند كل نقرة زر.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_147_51" style="">
<span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setShowAll</span><span class="pun">(!</span><span class="pln">showAll</span><span class="pun">)</span></pre>

<p>
	يتغير النص المكتوب على الزر حسب الحالة فمرة سيكون "important" ومرة "all":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_147_53" style="">
<span class="pln">show </span><span class="pun">{</span><span class="pln">showAll </span><span class="pun">?</span><span class="pln"> </span><span class="str">'important'</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">'all'</span><span class="pun">}</span></pre>

<p>
	ستجد شيفرة التطبيق الذي نعمل عليه في المسار part2-3 <a href="https://github.com/fullstack-hy2020/part2-notes/tree/part2-3" rel="external nofollow">ضمن المخزن المخصص على github</a>.
</p>

<h2>
	التمارين 2.6-2.10
</h2>

<p>
	سنطور التطبيق الذي سنبدأه في التمرين الأول خلال التمارين اللاحقة. يفضل أن تسلم في مثل هذه الحالات النسخة النهائية من التطبيق. ويمكنك الإشارة إلى ذلك إن أردت من خلال التعليقات ضمن شيفرتك.
</p>

<p>
	<strong>تحذير</strong>: تنشئ الأداة create-react-app مستودع git محلي يحتوي المشروع، إلا إن كان في المجلد مستودع محلي سابق. من المرجح أنك لا تريد أن يغدو المشروع مستودعًا، لهذا نفذ الأمر التالي<code>rm -rf .git</code> في مسار المشروع.
</p>

<h3>
	2.6 دليل الهاتف: الخطوة 1
</h3>

<p>
	صمم دليل هاتف بسيط. سنعمل في هذا القسم على إضافة الأسماء فقط. اكتب الشيفرة المناسبة لإضافة شخص إلى دليلك. يمكنك استخدام الشيفرة التالية كنقطة انطلاق للمكوِّن <code>App</code> الخاص بتطبيقك:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_147_55" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> useState </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> persons</span><span class="pun">,</span><span class="pln"> setPersons </span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">([</span><span class="pln">
    </span><span class="pun">{</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Arto Hellas'</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">])</span><span class="pln"> 
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> newName</span><span class="pun">,</span><span class="pln"> setNewName </span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="str">''</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="typ">Phonebook</span><span class="pun">&lt;/</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
          name</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">input </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="pln">button type</span><span class="pun">=</span><span class="str">"submit"</span><span class="pun">&gt;</span><span class="pln">add</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">form</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="typ">Numbers</span><span class="pun">&lt;/</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">...</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">App</span></pre>

<p>
	تستخدم قطعة الحالة <code>newName</code> في قيادة عنصر الإدخال في النموذج. من المفيد أحيانًا تصيير قطع الحالة أو المتغيرات لتظهر قيمها بشكل نصي لأغراض التنقيح. إذ يمكنك إضافة الشيفرة التالية مؤقتًا إلى العنصر الذي تصّيره:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_147_57" style="">
<span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">debug</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">newName</span><span class="pun">}&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span></pre>

<p>
	لا تنس الاستفادة مما تعلمته عن <a href="https://fullstackopen.com/en/part1/a_more_complex_state_debugging_react_apps" rel="external nofollow">تنقيح تطبيقات React</a> في القسم 1، كما سيمنحك الموسِّع <a href="https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi" rel="external nofollow">React developer tools</a> قدرة كبيرة على تتبع التغيرات التي تحدث في حالة التطبيق. بعد إتمامك العمل ستبدو واجهة التطبيق مشابهة للواجهة التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/phonebook_step1_005.png.4dfd4ee75e634fc8f382e419026cd156.png" data-fileid="55246" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="55246" data-unique="ajxbrafa8" src="https://academy.hsoub.com/uploads/monthly_2021_01/phonebook_step1_005.png.4dfd4ee75e634fc8f382e419026cd156.png" alt="phonebook_step1_005.png"></a>
</p>

<p>
	لاحظ في الشكل السابق كيف يُستخدم الموسِّع الذي ذكرناه.
</p>

<p>
	<strong>تذكر</strong>:
</p>

<ul>
<li>
		يمكنك أن تضع اسم الشخص كقيمة للخاصية <code>key</code>.
	</li>
	<li>
		تذكر أن تمنع التسليم الافتراضي للنموذج.
	</li>
</ul>
<h3>
	2.7 دليل الهاتف: الخطوة 2
</h3>

<p>
	امنع المستخدم من إدخال أسماء موجودة أصلًا في الدليل. استفد من <a href="https://wiki.hsoub.com/JavaScript/Array" rel="external">توابع المصفوفات</a> التي تقدمها JavaScript لإتمام المطلوب. وأظهر رسالة تحذير عندما يحاول المستخدم القيام بذلك باستخدام التابع <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/alert" rel="external nofollow">alert</a>.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/phonebook_step2_006.png.6e5a67b0ff7248772dfbc7059a1f37e8.png" data-fileid="55247" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="55247" data-unique="9u7f95ymo" src="https://academy.hsoub.com/uploads/monthly_2021_01/phonebook_step2_006.png.6e5a67b0ff7248772dfbc7059a1f37e8.png" alt="phonebook_step2_006.png"></a>
</p>

<p>
	<strong>تلميح</strong>: يفضل استخدام <a href="https://wiki.hsoub.com/JavaScript/Template_Literals" rel="external">القالب النصي</a> إذا أردت أن تضع قيمة متغير ما ضمن سلسلة نصية.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_147_59" style="">
<span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">newName</span><span class="pun">}</span><span class="pln"> is already added to phonebook</span><span class="pun">`</span></pre>

<p>
	فإن كانت قيمة المتغير <code>newName</code> هي Arto Hellas سيعيد القالب النصي ما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_147_61" style="">
<span class="pun">`</span><span class="typ">Arto</span><span class="pln"> </span><span class="typ">Hellas</span><span class="pln"> is already added to phonebook</span><span class="pun">`</span></pre>

<p>
	كما يمكن استعمال إشارة (+) بكل بساطة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_147_63" style="">
<span class="pln">newName </span><span class="pun">+</span><span class="pln"> </span><span class="str">' is already added to phonebook'</span></pre>

<p>
	طبعًا ستبدو شيفرتك إحترافية أكثر عندما تستخدم القالب النصي.
</p>

<h3>
	2.8 دليل الهاتف: الخطوة 3
</h3>

<p>
	اجعل المستخدم قادرًا على إضافة رقم الهاتف أيضًا، لذا عليك إضافة عنصر إدخال آخر إلى النموذج، وطبعًا إضافة معالج حدث مناسب:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_147_65" style="">
<span class="tag">&lt;form&gt;</span><span class="pln">
  </span><span class="tag">&lt;div&gt;</span><span class="pln">name: </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="tag">/&gt;&lt;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;div&gt;</span><span class="pln">number: </span><span class="tag">&lt;input</span><span class="pln"> </span><span class="tag">/&gt;&lt;/div&gt;</span><span class="pln">
  </span><span class="tag">&lt;div&gt;&lt;button</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"submit"</span><span class="tag">&gt;</span><span class="pln">add</span><span class="tag">&lt;/button&gt;&lt;/div&gt;</span><span class="pln">
</span><span class="tag">&lt;/form&gt;</span></pre>

<p>
	حتى هذه النقطة ستبدو واجهة التطبيق مشابه للصورة التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/phonebook_step3_007.png.39a52122327caa19c4f3bb8daf28f7db.png" data-fileid="55248" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="55248" data-unique="l7xrsedcl" src="https://academy.hsoub.com/uploads/monthly_2021_01/phonebook_step3_007.png.39a52122327caa19c4f3bb8daf28f7db.png" alt="phonebook_step3_007.png"></a>
</p>

<p>
	لاحظ كيف يقوم الموسٍّع بعمله!
</p>

<h3>
	2.9 دليل الهاتف: الخطوة 4 *
</h3>

<p>
	أضف للتطبيق إمكانية البحث عن الأشخاص بالاسم:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2021_01/phonebook_step4_008.png.b3d4e2304353165fec9f5bcfeddceaf0.png" data-fileid="55249" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="55249" data-unique="e3gyj0ade" src="https://academy.hsoub.com/uploads/monthly_2021_01/phonebook_step4_008.png.b3d4e2304353165fec9f5bcfeddceaf0.png" alt="phonebook_step4_008.png"></a>
</p>

<p>
	استخدم لذلك عنصر إدخال جديد وضعه خارج النموذج. توضح الصورة السابقة أنّ منطق الانتقاء غير حساس لحالة الأحرف أي البحث عن arto سيعطيك النتيجة Arto أيضًا إن وجدت.
</p>

<p>
	<strong>تذكر</strong>: أضف دائمًا بعض البيانات الجاهزة في تطبيقك كما فعلنا في الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_147_67" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">persons</span><span class="pun">,</span><span class="pln"> setPersons</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">([</span><span class="pln">
    </span><span class="pun">{</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Arto Hellas'</span><span class="pun">,</span><span class="pln"> number</span><span class="pun">:</span><span class="pln"> </span><span class="str">'040-123456'</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Ada Lovelace'</span><span class="pun">,</span><span class="pln"> number</span><span class="pun">:</span><span class="pln"> </span><span class="str">'39-44-5323523'</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Dan Abramov'</span><span class="pun">,</span><span class="pln"> number</span><span class="pun">:</span><span class="pln"> </span><span class="str">'12-43-234345'</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Mary Poppendieck'</span><span class="pun">,</span><span class="pln"> number</span><span class="pun">:</span><span class="pln"> </span><span class="str">'39-23-6423122'</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">])</span><span class="pln">

  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيوفر عليك ذلك عناء إدخال البيانات يدويًا كل مرة عند اختبار وظيفة جديدة.
</p>

<h3>
	2.10 دليل الهاتف: الخطوة 5
</h3>

<p>
	إن صممت تطبيقك ليستخدم مكوِّنًا واحدًا، أعد بناءه بوضع الأجزاء التي تراها مناسبة في مكوِّنات جديدة. ابق على حالة المكوِّن ومعالجات الأحداث ضمن المكوِّن الجذري <code>App</code>.
</p>

<p>
	يكفي أن تشكل ثلاثة مكوِّنات جديدة. يمكنك على سبيل المثال عزل عملية البحث في مكوِّن وكذلك النموذج الذي يُستخدم لإضافة الأشخاص وأيضًا عملية تصيير كل الأشخاص في الدليل أو عملية تصيير تفاصيل شخص واحد.
</p>

<p>
	يمكن أن يشبه المكوِّن الجذري بعد إعادة البناء الشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_147_69" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="typ">Phonebook</span><span class="pun">&lt;/</span><span class="pln">h2</span><span class="pun">&gt;</span><span class="pln">

      </span><span class="pun">&lt;</span><span class="typ">Filter</span><span class="pln"> </span><span class="pun">...</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">

      </span><span class="pun">&lt;</span><span class="pln">h3</span><span class="pun">&gt;</span><span class="typ">Add</span><span class="pln"> a </span><span class="kwd">new</span><span class="pun">&lt;/</span><span class="pln">h3</span><span class="pun">&gt;</span><span class="pln">

      </span><span class="pun">&lt;</span><span class="typ">PersonForm</span><span class="pln"> 
        </span><span class="pun">...</span><span class="pln">
      </span><span class="pun">/&gt;</span><span class="pln">

      </span><span class="pun">&lt;</span><span class="pln">h3</span><span class="pun">&gt;</span><span class="typ">Numbers</span><span class="pun">&lt;/</span><span class="pln">h3</span><span class="pun">&gt;</span><span class="pln">

      </span><span class="pun">&lt;</span><span class="typ">Persons</span><span class="pln"> </span><span class="pun">...</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيصيّر المكوِّن الجذري عنوان التطبيق فقط، وتتولى المكوِّنات الجديدة بقية المهام.
</p>

<p>
	<strong>تذكر</strong>: قد تواجهك المشاكل في هذا التمرين إن لم تعرف المكوِّنات في المكان الصحيح، ولعلك ستستفيد الآن من مراجعة الفقرة <a href="https://fullstackopen.com/en/part1/a_more_complex_state_debugging_react_apps#do-not-define-components-within-components" rel="external nofollow">لا تعرف مكوِّنًا داخل مكوِّن آخر</a> من القسم السابق.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://fullstackopen.com/en/part2/forms" rel="external nofollow">Forms</a> من سلسلة <a href="https://fullstackopen.com/en/" rel="external nofollow">Deep Dive Into Modern Web Development</a>
</p>
]]></description><guid isPermaLink="false">1095</guid><pubDate>Sun, 03 Jan 2021 13:00:00 +0000</pubDate></item><item><title>&#x62A;&#x635;&#x64A;&#x64A;&#x631; &#x645;&#x62C;&#x645;&#x648;&#x639;&#x629; &#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; &#x648;&#x645;&#x641;&#x647;&#x648;&#x645; &#x627;&#x644;&#x648;&#x62D;&#x62F;&#x627;&#x62A; &#x641;&#x64A; React</title><link>https://academy.hsoub.com/programming/javascript/react/%D8%AA%D8%B5%D9%8A%D9%8A%D8%B1-%D9%85%D8%AC%D9%85%D9%88%D8%B9%D8%A9-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D9%85%D9%81%D9%87%D9%88%D9%85-%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-%D9%81%D9%8A-react-r1094/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_01/p8-3.jpg.26e887ba6951b4fae36a6b8641265433.jpg" /></p>

<p>
	لنلقي نظرة سريعة على المواضيع التي بدت صعبة في النسخة السابقة من المنهاج قبل أن ننتقل إلى موضوع جديد.
</p>

<h2>
	التعليمة console.log
</h2>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p>
		ما الفرق بين مبرمج JavaScript محترف وآخر هاوٍ؟ يستعمل المبرمج المحترف التعليمة console.log من 10 إلى 100 مرة أكثر.
	</p>
</blockquote>

<p>
	سيبدو ذلك -رغم المفارقة- صحيحًا على الرغم من أن الهاوي سيحتاج هذه التعليمة أو غيرها من طرق التنقيح أكثر مما يحتاج إليه المحترف. عندما يتوقف تطبيقك عن العمل، لا تحاول أن تخمن مصدر الخطأ فحسب، بل استخدم تعليمة <code>log</code> أو غيرها من وسائل التنقيح.
</p>

<p>
	<strong>تذكر</strong> لا تضم ما تريد إظهاره على الطرفية مستخدمًا إشارة الجمع (+) كأسلوب Java:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_7" style="">
<span class="pln">console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'props value is'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> props</span><span class="pun">)</span></pre>

<p>
	بل افصل الأشياء التي تريد طباعتها بفاصلة (,):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_9" style="">
<span class="pln">console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'props value is'</span><span class="pun">,</span><span class="pln"> props</span><span class="pun">)</span></pre>

<p>
	إن استخدمت أسلوب Java فلن تحصل على النتيجة المطلوبة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_11" style="">
<span class="pln">props value is </span><span class="pun">[</span><span class="typ">Object</span><span class="pln"> object</span><span class="pun">]</span></pre>

<p>
	بينما لو استخدمت الفاصلة لتمييز القيم التي تريد إظهارها على الطرفية فستُطبع بشكل قيم نصية منفصلة ومفهومة. لمعرفة المزيد، راجع <a href="https://academy.hsoub.com/programming/javascript/react/%D8%AD%D8%A7%D9%84%D8%A7%D8%AA-%D8%A3%D8%B9%D9%82%D8%AF-%D9%84%D9%84%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-%D9%88%D8%AA%D9%86%D9%82%D9%8A%D8%AD-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-react-r1075/" rel="">بعض الأفكار التي تحدثنا عنها</a> بشأن تنقيح تطبيقات React.
</p>

<p>
	<strong>نصيحة للاحتراف: استخدام مقاطع شيفرة Visual Studio</strong><br>
	يمكن بسهولة إنشاء مقاطع شيفرة باستخدام Visual studio، حيث تعتبر هذه المقاطع أسطرًا برمجية قابلة لإعادة الاستخدام. وتشابه في عملها أسطر sout في برنامج Netbeans. يمكنك إيجاد المزيد من <a href="https://code.visualstudio.com/docs/editor/userdefinedsnippets#creating-your-own-snippets" rel="external nofollow">الإرشادات</a> حول إنشاء واستخدام المقاطع من خلال الإنترنت. كما يمكنك البحث عن مقاطع جاهزة على شكل إضافات لبرنامج Visual Studio مثل الإضافة xabikos.ReactSnippets.
</p>

<p>
	يعتبر المقطع الذي ينفذ الأمر <code>()console.log leg</code> في الشيفرة التالية الأكثر أهمية حيث يوضح الأمر<code>clog</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_13" style="">
<span class="pun">{</span><span class="pln">
 </span><span class="str">"console.log"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"prefix"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"clog"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"body"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
      </span><span class="str">"console.log('$1')"</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">],</span><span class="pln">
    </span><span class="str">"description"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Log output to console"</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	مصفوفات JavaScript
</h2>

<p>
	انطلاقًا من هذه النقطة سنستخدم توابعًا للتعامل مع المصفوفات في JavaScript وفق أسلوب البرمجة بالدوال مثل التوابع <code>find</code> و<code>filter</code> و<code>map</code>. تشابه هذه التوابع في مبدأ عملها "المجاري (Streams)" في Java 8 التي اعتُمدت خلال السنوات القليلة الماضية في مقررات قسم علوم الحاسب في جامعة هلسنكي. إن بدا لك غريبًا أسلوب البرمجة بالدوال مع المصفوفات، يمكنك متابعة مقاطع الفيديو الأجنبية التالية:
</p>

<ul>
<li>
		<a href="https://www.youtube.com/playlist?list=PL0zVEGEvSaeEd9hlmCXrk5yUyqUag-n84" rel="external nofollow">Functional Programming</a>
	</li>
	<li>
		<a href="https://www.youtube.com/watch?v=BMUiFMZr7vk&amp;list=PL0zVEGEvSaeEd9hlmCXrk5yUyqUag-n84" rel="external nofollow">Higher-order functions</a>
	</li>
	<li>
		<a href="https://www.youtube.com/watch?v=bCqtb-Z5YGQ&amp;list=PL0zVEGEvSaeEd9hlmCXrk5yUyqUag-n84&amp;index=2" rel="external nofollow">Map</a>
	</li>
	<li>
		<a href="https://www.youtube.com/watch?v=Wl98eZpkp-c&amp;t=31s" rel="external nofollow">Reduce basics</a>
	</li>
</ul>
<h2>
	معالجات الأحداث: نظرة ثانية
</h2>

<p>
	أثبت مفهوم معالجة الأحداث أنه صعب استنادًا إلى تقييمنا لمنهاج العام الفائت. لذا من الأجدى أن تلقي نظرة ثانية على هذا الموضوع الذي ناقشناه في الفصل السابق ضمن فقرة "<a href="https://academy.hsoub.com/programming/javascript/react/%D8%AD%D8%A7%D9%84%D8%A7%D8%AA-%D8%A3%D8%B9%D9%82%D8%AF-%D9%84%D9%84%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-%D9%88%D8%AA%D9%86%D9%82%D9%8A%D8%AD-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-react-r1075/" rel="">عودة إلى معالجة الأحداث</a>" إذا أردت إنعاش معلوماتك. كما برزت تساؤلات عدة حول تمرير معالجات الأحداث إلى المكوِّن الابن للمكوِّن الذي أنشأناه سابقًا <code>App</code>، لذلك يفضل مراجعة <a href="https://academy.hsoub.com/programming/javascript/react/%D8%AD%D8%A7%D9%84%D8%A7%D8%AA-%D8%A3%D8%B9%D9%82%D8%AF-%D9%84%D9%84%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-%D9%88%D8%AA%D9%86%D9%82%D9%8A%D8%AD-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-react-r1075/" rel="">هذا الموضوع</a>.
</p>

<h2>
	تصيير مجموعات البيانات
</h2>

<p>
	سنعمل الآن على الواجهة الأمامية للتطبيقات (frontend) أو ما يعرف بكتابة شيفرة التطبيق من جهة المتصفح. لنبدأ بتطبيق React مشابه للمثال النموذجي الذي رأيناه في مقال <a href="https://academy.hsoub.com/programming/javascript/react/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r1071/" rel="">أساسيات بناء تطبيقات الويب</a>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_20" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">ReactDOM</span><span class="pln"> from </span><span class="str">'react-dom'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> notes </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'HTML is easy'</span><span class="pun">,</span><span class="pln">
    date</span><span class="pun">:</span><span class="pln"> </span><span class="str">'2019-05-30T17:30:31.098Z'</span><span class="pun">,</span><span class="pln">
    important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Browser can execute only Javascript'</span><span class="pun">,</span><span class="pln">
    date</span><span class="pun">:</span><span class="pln"> </span><span class="str">'2019-05-30T18:39:34.091Z'</span><span class="pun">,</span><span class="pln">
    important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'GET and POST are the most important methods of HTTP protocol'</span><span class="pun">,</span><span class="pln">
    date</span><span class="pun">:</span><span class="pln"> </span><span class="str">'2019-05-30T19:20:14.298Z'</span><span class="pun">,</span><span class="pln">
    important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">]</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> notes </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> props

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Notes</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">li</span><span class="pun">&gt;{</span><span class="pln">notes</span><span class="pun">[</span><span class="lit">0</span><span class="pun">].</span><span class="pln">content</span><span class="pun">}&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">li</span><span class="pun">&gt;{</span><span class="pln">notes</span><span class="pun">[</span><span class="lit">1</span><span class="pun">].</span><span class="pln">content</span><span class="pun">}&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">li</span><span class="pun">&gt;{</span><span class="pln">notes</span><span class="pun">[</span><span class="lit">2</span><span class="pun">].</span><span class="pln">content</span><span class="pun">}&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="typ">ReactDOM</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="typ">App</span><span class="pln"> notes</span><span class="pun">={</span><span class="pln">notes</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;,</span><span class="pln">
  document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'root'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">)</span></pre>

<p>
	تحتوي كل ملاحظة على قيمة نصية وعبارة زمنية وقيمة منطقية (Boolean) تحدد إذا ما كانت الملاحظة هامة أم لا وكذلك قيمة فريدة (unique value) لتمييز الملاحظة تدعى <code>id</code>. يعمل التطبيق السابق على مبدأ وجود ثلاث ملاحظات فقط في المصفوفة، وتصيّر كل ملاحظة باستخدام القيمة <code>id</code> مباشرة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_9974_22" style="">
<span class="tag">&lt;li&gt;</span><span class="pln">{notes[1].content}</span><span class="tag">&lt;/li&gt;</span></pre>

<p>
	لكن من الأفضل أن نظهر المعلومات المستخلصة من المصفوفة على شكل عنصر React باستخدام الدالة <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map" rel="external nofollow">map</a>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_24" style="">
<span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">li</span><span class="pun">&gt;{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">content</span><span class="pun">}&lt;/</span><span class="pln">li</span><span class="pun">&gt;)</span></pre>

<p>
	ستكون النتيجة مصفوفة من العناصر <code>li</code>:
</p>

<pre class="ipsCode">
[
  &lt;li&gt;HTML is easy&lt;/li&gt;,
  &lt;li&gt;Browser can execute only Javascript&lt;/li&gt;,
  &lt;li&gt;GET and POST are the most important methods of HTTP protocol&lt;/li&gt;,
]
</pre>

<p>
	يمكن إضافتها إلى القائمة <code>ul</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_27" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> notes </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> props
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Notes</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">li</span><span class="pun">&gt;{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">content</span><span class="pun">}&lt;/</span><span class="pln">li</span><span class="pun">&gt;)}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	انتبه لضرورة وضع شيفرة JavaScript -الموجودة ضمن قالب JSX- داخل أقواس معقوصة كي يتم تنفيذها. سنجعل الشيفرة أكثر وضوحًا بنشر تصريح الدالة السهمية ليمتد على عدة أسطر:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_29" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> notes </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> props

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Notes</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">

     </span><span class="pun">&lt;</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">li</span><span class="pun">&gt;{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">content</span><span class="pun">}&lt;/</span><span class="pln">li</span><span class="pun">&gt;)}</span><span class="pln">
     </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
   </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	الصفات المفتاحية key-attribute
</h2>

<p>
	على الرغم من أن التطبيق سيعمل بشكل طبيعي، إلّا أن تحذيرًا مزعجًا يظهر على الطرفية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="55233" href="https://academy.hsoub.com/uploads/monthly_2021_01/unique_value_01.png.e2a10ff321c1b45179fa95ff246e0a67.png" rel=""><img alt="unique_value_01.png" class="ipsImage ipsImage_thumbnailed" data-fileid="55233" data-unique="rdehutpys" src="https://academy.hsoub.com/uploads/monthly_2021_01/unique_value_01.png.e2a10ff321c1b45179fa95ff246e0a67.png"></a>
</p>

<p>
	تشير التوجيهات في الصفحة المرتبطة برسالة الخطأ، ضرورة امتلاك عناصر القوائم التي أنشأها التابع <code>map</code> قيمًا مفتاحية فريدة وهي صفات تدعى <code>key</code>. لنضف إذا المفاتيح المناسبة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_31" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> notes </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> props

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Notes</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> 
          </span><span class="pun">&lt;</span><span class="pln">li key</span><span class="pun">={</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}&gt;{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">content</span><span class="pun">}&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">        
         </span><span class="pun">)}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وهكذا ستختفي رسالة التحذير. تستخدم React الصفات المفتاحية لتقرر الآلية التي تحدّث فيها مظهر التطبيق عندما يعاد تصيير مكوِّن. يمكنك دومًا استخدام وثائق React لمعرفة <a href="https://wiki.hsoub.com/React/reconciliation#.D8.A7.D9.84.D8.AA.D9.83.D8.B1.D8.A7.D8.B1_.D8.B9.D9.84.D9.89_.D8.A7.D9.84.D8.B9.D9.86.D8.A7.D8.B5.D8.B1_.D8.A7.D9.84.D8.A3.D8.A8.D9.86.D8.A7.D8.A1" rel="external">المزيد</a>.
</p>

<h2>
	التابع Map
</h2>

<p>
	إنّ فهمك لآلية عمل التابع <a href="https://www.google.com/url?q=https://wiki.hsoub.com/JavaScript/Array%23Array.prototype.map.28.29.E2.80.8E&amp;sa=D&amp;ust=1599743997826000&amp;usg=AFQjCNFMk7ZvUxdVbrqPMh5A409pXlMusw" rel="external nofollow">map</a> عند التعامل مع المصفوفات أمر حيوي سيلزمك دائمًا. يحتوي التطبيق على مصفوفة تدعى <code>notes</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_33" style="">
<span class="kwd">const</span><span class="pln"> notes </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'HTML is easy'</span><span class="pun">,</span><span class="pln">
    date</span><span class="pun">:</span><span class="pln"> </span><span class="str">'2019-05-30T17:30:31.098Z'</span><span class="pun">,</span><span class="pln">
    important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Browser can execute only Javascript'</span><span class="pun">,</span><span class="pln">
    date</span><span class="pun">:</span><span class="pln"> </span><span class="str">'2019-05-30T18:39:34.091Z'</span><span class="pun">,</span><span class="pln">
    important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln">
    content</span><span class="pun">:</span><span class="pln"> </span><span class="str">'GET and POST are the most important methods of HTTP protocol'</span><span class="pun">,</span><span class="pln">
    date</span><span class="pun">:</span><span class="pln"> </span><span class="str">'2019-05-30T19:20:14.298Z'</span><span class="pun">,</span><span class="pln">
    important</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">]</span></pre>

<p>
	لنتوقف قليلًا ونرى كيف يعمل <code>map</code>. لنقل أن الشيفرة التالية قد أضيفت إلى نهاية الملف:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_35" style="">
<span class="kwd">const</span><span class="pln"> result </span><span class="pun">=</span><span class="pln"> notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">)</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">result</span><span class="pun">)</span></pre>

<p>
	سينشئ التابع <code>map</code> مصفوفة جديدة قيمها [1,2,3] انطلاقًا من عناصر المصفوفة الأصلية. ويستخدم دالة كمُعامل له. ولهذه الدالة الشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_37" style="">
<span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> note</span><span class="pun">.</span><span class="pln">id</span></pre>

<p>
	تمثل الشيفرة السابقة الشكل المختصر لدالة سهمية تعطى بشكلها الكامل على النحو:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_39" style="">
<span class="pun">(</span><span class="pln">note</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> note</span><span class="pun">.</span><span class="pln">id
</span><span class="pun">}</span></pre>

<p>
	تقبل الدالة السابقة الكائن <code>note</code> كمُعامل، وتعيد قيمة الحقل <code>id</code> منه. لكن إن غيرنا الشيفرة لتصبح:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_41" style="">
<span class="kwd">const</span><span class="pln"> result </span><span class="pun">=</span><span class="pln"> notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> note</span><span class="pun">.</span><span class="pln">content</span><span class="pun">)</span></pre>

<p>
	ستكون النتيجة مصفوفة تضم محتوى الملاحظات. هذه الشيفرة قريبة جدًا من شيفرة React التي استخدمناها سابقًا:
</p>

<pre class="ipsCode">
notes.map(note =&gt;
  &lt;li key={note.id}&gt;{note.content}&lt;/li&gt;
)
</pre>

<p>
	والتي تنشئ عناصر <code>li</code> تضم المحتوى النصي للملاحظات. وطالما أن الدالة مُرّرت كمعامل إلى التابع <code>map</code> لإظهار العناصر، يجب وضع قيم المتغيّرات داخل الأقواس المعقوصة.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_43" style="">
<span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">li key</span><span class="pun">={</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}&gt;{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">content</span><span class="pun">}&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span></pre>

<p>
	حاول أن تعرف ما الذي سيحدث لو أهملت تلك الأقواس. سيزعجك استخدام الأقواس المعقوصة في البداية لكنك ستعتاد على ذلك وستساعدك React بإظهارها مباشرة نتائج شيفرتك.
</p>

<h2>
	استخدام مصفوفة القرائن كمفاتيح: الأسلوب المعاكس
</h2>

<p>
	كان بإمكاننا إخفاء رسالة الخطأ السابقة باستخدام مصفوفة القرائن (Array indexes) كمفاتيح، حيث نستخلص هذه القرائن بتمرير معامل آخر إلى دالة الاستدعاء التي استخدمناها كمعامل للتابع <code>map</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_46" style="">
<span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">((</span><span class="pln">note</span><span class="pun">,</span><span class="pln"> i</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">...)</span></pre>

<p>
	عندما نستدعي الدالة بالشكل السابق ستأخذ <code>i</code> قيمة القرينة التي تشير إلى موقع الملاحظة في الكائن <code>note</code>، وبهذا الأسلوب سنعرّف طريقةً لإنشاء المطلوب دون أخطاء:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_48" style="">
<span class="pun">&lt;</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">((</span><span class="pln">note</span><span class="pun">,</span><span class="pln"> i</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> 
    </span><span class="pun">&lt;</span><span class="pln">li key</span><span class="pun">={</span><span class="pln">i</span><span class="pun">}&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">content</span><span class="pun">}</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)}</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span></pre>

<p>
	على الرغم من ذلك لا نوصي باتباع هذا الأسلوب نظرًا للمشاكل غير المتوقعة التي يمكن أن تحدث حتى لو بدا أنّ التطبيق يعمل بشكل جيد. يمكنك الاطلاع أكثر بقراءة مقالات <a href="https://medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318" rel="external nofollow">تتعلق بالموضوع</a>.
</p>

<h2>
	إعادة تكوين الوحدات
</h2>

<p>
	لندعّم الشيفرة التي كتبناها قليلًا. طالما أن اهتمامنا ينحصر في الحقل<code>notes</code> فقط من خصائص المكوِّن، لنستخلص قيمة الحقل المطلوب مباشرة بطريقة <a href="https://www.google.com/url?q=https://wiki.hsoub.com/JavaScript/Destructuring_Assignment&amp;sa=D&amp;ust=1599743997827000&amp;usg=AFQjCNEUnpcMhrtz1S-4zIc44UOCVzjFDA" rel="external nofollow">التفكيك</a>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_50" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> notes </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Notes</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> 
          </span><span class="pun">&lt;</span><span class="pln">li key</span><span class="pun">={</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}&gt;</span><span class="pln">
            </span><span class="pun">{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">content</span><span class="pun">}</span><span class="pln">
          </span><span class="pun">&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">)}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وإن أردت تذكّر معلوماتك عن موضوع التفكيك راجع <a href="https://academy.hsoub.com/programming/javascript/react/%D8%AD%D8%A7%D9%84%D8%A9-%D8%A7%D9%84%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-component-state-%D9%88%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D8%AD%D8%AF%D8%A7%D8%AA-event-handlers-%D9%81%D9%8A-react-r1074/" rel="">فقرة التفكيك</a> في القسم السابق. سنعرف الآن مكوِّنًا جديدًا <code>Note</code> لعرض الملاحظة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_52" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Note</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> note </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(&lt;</span><span class="pln">li</span><span class="pun">&gt;{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">content</span><span class="pun">}&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">  </span><span class="pun">)}</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> notes </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Notes</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">note </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">&lt;</span><span class="typ">Note</span><span class="pln"> key</span><span class="pun">={</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}</span><span class="pln"> note</span><span class="pun">={</span><span class="pln">note</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln"> </span><span class="pun">)}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لاحظ أن الصفة المفتاحية ارتبطت الآن بالمكوِّن <code>Note</code> وليس بالعنصر <code>li</code>.
</p>

<p>
	يمكن كتابة تطبيق React بأكمله ضمن ملف واحد. لكن جرت العادة على كتابة كل مكوِّن في ملف خاص على شكل <strong>وحدة ES6</strong>، على الرغم من أن هذا الأسلوب ليس عمليًا جدًا. لقد استخدمنا الوحدات منذ البداية في شيفرتنا كما فعلنا في أول سطرين من الملف:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_54" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">ReactDOM</span><span class="pln"> from </span><span class="str">'react-dom'</span></pre>

<p>
	فلقد <a href="https://wiki.hsoub.com/JavaScript/import" rel="external">أدرجنا</a> وحدتين لاستخدامهما في الملف. حيث أسندت الوحدة <code>react</code> إلى متغيّر يدعى <code>React</code> وكذلك أسندت الوحدة <code>react-dom</code> إلى المتغيّر <code>ReactDOM</code>. لننقل الآن المكوِّن <code>Note</code> إلى وحدته الخاصة. توضع المكوِّنات عادة في مجلد يدعى components ضمن المجلد src الموجود في المجلد الرئيسي للتطبيق، ويفضل تسمية الملف باسم المكوِّن. دعونا ننفذ ما ذكرناه ونضع المكوِّن <code>Note</code> في ملف جديد يدعى Note.js كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_56" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Note</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> note </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">li</span><span class="pun">&gt;{</span><span class="pln">note</span><span class="pun">.</span><span class="pln">content</span><span class="pun">}&lt;/</span><span class="pln">li</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">Note</span></pre>

<p>
	لاحظ أننا أدرجنا React في السطر الأول لأن المكوِّن هو مكوِّن React. <a href="https://wiki.hsoub.com/JavaScript/export" rel="external">سيصدّر</a> السطر الأخير الوحدة الجديدة التي عرفناها باسم Note لكي تستخدم في مكان آخر. سندرج الآن الوحدة الجديدة في الملف index.js:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_58" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">ReactDOM</span><span class="pln"> from </span><span class="str">'react-dom'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Note</span><span class="pln"> from </span><span class="str">'./components/Note'</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> notes </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وهكذا يمكن استخدام الوحدة الجديدة بإسنادها إلى المتغيّر <code>Note</code>. وتذكر كتابة عنوان الوحدة بطريقة العنوان النسبي عند إدراجها.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_60" style="">
<span class="str">'./components/Note'</span></pre>

<p>
	تشير النقطة (.) في بداية العنوان إلى المسار الحالي وبالتالي فإن الملف Note.js موجود ضمن المجلد الفرعي component والموجود ضمن المسار الحالي (المجلد الذي يحوي التطبيق).
</p>

<p>
	<strong>ملاحظة</strong>: يمكن إغفال كتابة اللاحقة js .
</p>

<p>
	لنصرح الآن عن المكوِّن <code>App</code> أيضًا في وحدة خاصة به. وطالما أنه المكوِّن الجذري سنضعه مباشرة في المجلد src:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_62" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">Note</span><span class="pln"> from </span><span class="str">'./components/Note'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> notes </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Notes</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">notes</span><span class="pun">.</span><span class="pln">map</span><span class="pun">((</span><span class="pln">note</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> 
          </span><span class="pun">&lt;</span><span class="typ">Note</span><span class="pln"> key</span><span class="pun">={</span><span class="pln">note</span><span class="pun">.</span><span class="pln">id</span><span class="pun">}</span><span class="pln"> note</span><span class="pun">={</span><span class="pln">note</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">)}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">ul</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">App</span></pre>

<p>
	ما بقي إذًا في الملف index.js هو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_64" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">ReactDOM</span><span class="pln"> from </span><span class="str">'react-dom'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> from </span><span class="str">'./App'</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> notes </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">]</span><span class="pln">

</span><span class="typ">ReactDOM</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="typ">App</span><span class="pln"> notes</span><span class="pun">={</span><span class="pln">notes</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;,</span><span class="pln">
  document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'root'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">)</span></pre>

<p>
	للوحدات استعمالات أخرى عديدة بالإضافة إلى التصريح عن المكوِّنات في ملفاتها الخاصة، سنعود إليها لاحقًا في المنهاج. ستجد شيفرة التطبيق الحالي على موقع <a href="https://github.com/fullstack-hy2020/part2-notes/tree/part2-1" rel="external nofollow">GitHub</a>. يحوي المسار الرئيسي للمخزن كما ستلاحظ شيفرات للنسخ التي سنطورها لاحقًا، لكن النسخة الحالية في المسار <a href="https://github.com/fullstack-hy2020/part2-notes/tree/part2-1" rel="external nofollow">part2-1</a>.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="55228" href="https://academy.hsoub.com/uploads/monthly_2021_01/app_add_github_002.png.7274197b77aa7c633dbb1befb81fe64b.png" rel=""><img alt="app_add_github_002.png" class="ipsImage ipsImage_thumbnailed" data-fileid="55228" data-unique="tub813uu2" src="https://academy.hsoub.com/uploads/monthly_2021_01/app_add_github_002.png.7274197b77aa7c633dbb1befb81fe64b.png"></a>
</p>

<p>
	قبل أن تشغّل التطبيق باستعمال الأمر <code>npm start</code>، نفذ أولًا الأمر <code>npm install</code>.
</p>

<h2>
	عندما ينهار التطبيق
</h2>

<p>
	سترى في بداياتك البرمجية أو حتى بعد 30 عامًا من كتابة الشيفرات أن التطبيق قد ينهار أحيانًا وبشكل مفاجئ. وسيكون الأمر أسوأ في اللغات التي يمكن كتابة تعليماتها بشكل ديناميكي أثناء التنفيذ مثل JavaScript. فلا يتاح عندها للمتصفح من التحقق مثلًا من نوع البيانات التي يحملها متغيّر أو التي تمرر لدالة.
</p>

<p>
	يظهر الشكل التالي مثالًا عن انهيار تطبيق React:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="55229" href="https://academy.hsoub.com/uploads/monthly_2021_01/app_break_003.png.83e1eca3bb21897f96e2e8c07918d39e.png" rel=""><img alt="app_break_003.png" class="ipsImage ipsImage_thumbnailed" data-fileid="55229" data-unique="q2m170dk1" src="https://academy.hsoub.com/uploads/monthly_2021_01/app_break_003.png.83e1eca3bb21897f96e2e8c07918d39e.png"></a>
</p>

<p>
	سيكون مخرجك الوحيد من المأزق هو الطباعة على الطرفية. إنّ الشيفرة المسؤولة عن الانهيار في حالتنا هي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_66" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Course</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> course </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
   </span><span class="pun">&lt;</span><span class="typ">Header</span><span class="pln"> course</span><span class="pun">={</span><span class="pln">course</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> course </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ...</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Course</span><span class="pln"> course</span><span class="pun">={</span><span class="pln">course</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سنقتفي أثر الخطأ بإضافة التعليمة <code>console.log</code> إلى الشيفرة. وطالما أن المكوِّن <code>App</code> سيصيّر أولًا فمن المفيد وضع أول تعليمة طباعة ضمنه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_68" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> course </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ...</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'App works...'</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="com">// ..</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	عليك طبعًا النزول إلى الأسفل مرورًا بقائمة الأخطاء الطويلة حتى ترى نتيجة الطباعة.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="55234" href="https://academy.hsoub.com/uploads/monthly_2021_01/using_console_log_004.png.58cbe3fa40640e6273fd645a66991c63.png" rel=""><img alt="using_console_log_004.png" class="ipsImage ipsImage_thumbnailed" data-fileid="55234" data-unique="h394phtoj" src="https://academy.hsoub.com/uploads/monthly_2021_01/using_console_log_004.png.58cbe3fa40640e6273fd645a66991c63.png"></a>
</p>

<p>
	حالما تتأكد من أن الأمور جيدة حتى نقطة معينة، عليك نقل تعليمة الطباعة إلى نقطة أعمق. وتذكر أن التصريح عن مكوِّن بعبارة واحدة أو عن دالة دون أن تعيد قيمة، سيجعل الطباعة على الطرفية أصعب.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_70" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Course</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> course </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
   </span><span class="pun">&lt;</span><span class="typ">Header</span><span class="pln"> course</span><span class="pun">={</span><span class="pln">course</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">)</span></pre>

<p>
	لذا غيًر تصريح المكوِّن إلى شكله النموذجي حتى تستطيع الطباعة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_72" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Course</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> course </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">course</span><span class="pun">)</span><span class="pln">  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">Header</span><span class="pln"> course</span><span class="pun">={</span><span class="pln">course</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	قد يكون السبب الأساسي للمشكلة في أحيانٍ كثيرة متعلقًا بالخصائص التي تظهر بأنواع مختلفة عن المتوقع أو التي تستدعى بأسماء مختلفة عن أسمائها الفعلية. وكنتيجة لذلك، ستخفق عملية التفكيك. ويدل على ذلك التخلص من الأخطاء بمجرد إزالة عملية التفكيك، حيث يمكن معرفة المحتوى الفعلي للخصائص.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_74" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Course</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln">  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> course </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> props
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">Header</span><span class="pln"> course</span><span class="pun">={</span><span class="pln">course</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	إن لم تُحل المشكلة، لا يمكنك عندها سوى اصطياد الأخطاء بزرع تعليمة الطباعة <code>console.log</code> في أماكن مختلفة من الشيفرة.
</p>

<p>
	<em>أضيفت هذه الفقرة لمادة المنهاج بعد أن أخفقت الوحدة التي تمثل حلًا للسؤال التالي بشكل كامل (نظرًا لخطأ في نمط الخصائص) وتوجب علي البحث عن السبب باستخدام تعليمة الطباعة.</em>
</p>

<h2>
	التمارين 2.1 - 2.5
</h2>

<p>
	تسلّم التمارين عبر GitHub ومن ثم يشار إلى إكمالها ضمن منظومة <a href="https://studies.cs.helsinki.fi/stats/courses/fullstackopen" rel="external nofollow">تسليم الملفات</a>. يمكنك أن تضع جميع التمارين في مخزن واحد أو استخدم مخازن مختلفة. إذا وضعت تمارين الأقسام المختلفة في مخزن واحد، احرص على تسمية المجلدات ضمنه بشكل مناسب.
</p>

<p>
	تُسلَّم تمارين كل قسم دفعة واحدة، فلا يمكنك تسليم أية تمارين أنجزتها مؤخرًا من قسم ما إذا كنت قد سلمت غيرها من القسم ذاته.
</p>

<p>
	يضم هذا القسم تمارين أكثر من القسمين السابقين، لا تسلم أيًا منها حتى تنجزها كلها.
</p>

<p>
	<strong>تحذير</strong>: سيجعل create_react_app المشروع مستودع git إلا إذا أنشأت مشروعك داخل مستودع موجود مسبقًا. لن تريد فعل ذلك على الأغلب، لذا نفذ الأمر <code>rm -rf .git</code> عند جذر مشروعك.
</p>

<h3>
	2.1 معلومات عن المنهاج: الخطوة 6
</h3>

<p>
	سننهي في هذا التمرين تصيير محتوى المنهاج الذي استعرضناه في التمارين 1.1-1.5. يمكنك البدء من الشيفرة الموجودة في نماذج الأجوبة. ستجد نماذج أجوبة القسم 1 في <a href="https://studies.cs.helsinki.fi/stats/courses/fullstackopen" rel="external nofollow">منظومة تسليم الملفات</a>. انقر على my submissions في الأعلى ثم انقر على show الموجودة ضمن العمود solutions في السطر المخصص للقسم 1. انقر على الملف index.js للاطلاع على حل تمرين "معلومات عن المنهاج course info" تحت عبارة kurssitiedot التي تعني (معلومات عن المنهاج).
</p>

<p>
	<strong>تنبيه</strong>: إذا نسخت مشروعًا من مكان لآخر، سيتوجب عليك حذف المجلد node_modules وإعادة تثبيت ملفات الارتباط (Dependencies) مرة أخرى بتنفيذ الأمر <code>npm install</code> قبل أن تشغل التطبيق.
</p>

<p>
	لا يفضل أن تنسخ المحتوى الكامل لتطبيق أو أن تضيف المجلد node_modules إلى منظومة التحكم بالإصدار أو أن تقوم بكلا العملين.
</p>

<p>
	لنغيّر الآن المكوِّن <code>App</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_76" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> course </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
    name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Half Stack application development'</span><span class="pun">,</span><span class="pln">
    parts</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">
        name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Fundamentals of React'</span><span class="pun">,</span><span class="pln">
        exercises</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln">
        id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">
        name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Using props to pass data'</span><span class="pun">,</span><span class="pln">
        exercises</span><span class="pun">:</span><span class="pln"> </span><span class="lit">7</span><span class="pun">,</span><span class="pln">
        id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">
        name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'State of a component'</span><span class="pun">,</span><span class="pln">
        exercises</span><span class="pun">:</span><span class="pln"> </span><span class="lit">14</span><span class="pun">,</span><span class="pln">
        id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">]</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">&lt;</span><span class="typ">Course</span><span class="pln"> course</span><span class="pun">={</span><span class="pln">course</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	عّرف مكوِّنًا يدعى Course مسؤولًا عن تنسيق منهاج واحد. يمكن أن يتخذ التطبيق الهيكلية التالية:
</p>

<pre class="ipsCode">
App
  Course
    Header
    Content
      Part
      Part
      ...
</pre>

<p>
	سيضم المكوِّن <code>Course</code> كل المكوِّنات التي عرّفناها في القسم السابق والمسؤولة عن تصيير اسم المنهاج وأقسامه. ستبدو الصفحة بعد التصيير على الشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="55231" href="https://academy.hsoub.com/uploads/monthly_2021_01/comp_course_render_005.png.f2645ff1e8489ed5383a8ba72e5026b2.png" rel=""><img alt="comp_course_render_005.png" class="ipsImage ipsImage_thumbnailed" data-fileid="55231" data-unique="g5yk4rs0g" src="https://academy.hsoub.com/uploads/monthly_2021_01/comp_course_render_005.png.f2645ff1e8489ed5383a8ba72e5026b2.png"></a>
</p>

<p>
	ليس عليك جمع عدد التمارين بعد. لكن يجب عليك التأكد من أن التطبيق يعمل بشكل جيد بغض النظر عن عدد الأقسام في المنهاج. أي أنه سيعمل لو أزلت أو أضفت أقسامًا. واحرص على عدم ظهور أخطاء على الطرفية.
</p>

<h3>
	2.2 معلومات عن المنهاج: الخطوة 7
</h3>

<p>
	أظهر عدد التمارين الكلية في المنهاج.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="55232" href="https://academy.hsoub.com/uploads/monthly_2021_01/show_exe_sum_006.png.c5d351043482befb581bb35962959d28.png" rel=""><img alt="show_exe_sum_006.png" class="ipsImage ipsImage_thumbnailed" data-fileid="55232" data-unique="tsuyh3lnq" src="https://academy.hsoub.com/uploads/monthly_2021_01/show_exe_sum_006.png.c5d351043482befb581bb35962959d28.png"></a>
</p>

<h3>
	2.3 معلومات عن المنهاج: الخطوة 8 *
</h3>

<p>
	إن لم تجد طريقة لحل التمرين السابق، احسب العدد الكلي للتمارين باستخدام التابع <a href="https://wiki.hsoub.com/JavaScript/Array/reduce" rel="external">reduce</a> الذي يستعمل مع المصفوفات.
</p>

<p>
	<strong>نصيحة للاحتراف 1</strong>: إن بدت شيفرتك بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_79" style="">
<span class="kwd">const</span><span class="pln"> total </span><span class="pun">=</span><span class="pln"> 
  parts</span><span class="pun">.</span><span class="pln">reduce</span><span class="pun">((</span><span class="pln">s</span><span class="pun">,</span><span class="pln"> p</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> someMagicHere</span><span class="pun">)</span></pre>

<p>
	ولم تعمل، يجدر بك استخدام تعليمة الطباعة على الطرفية، والتي تتطلب إعادة كتابة الدالة السهمية بشكلها الكامل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_81" style="">
<span class="kwd">const</span><span class="pln"> total </span><span class="pun">=</span><span class="pln"> parts</span><span class="pun">.</span><span class="pln">reduce</span><span class="pun">((</span><span class="pln">s</span><span class="pun">,</span><span class="pln"> p</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'what is happening'</span><span class="pun">,</span><span class="pln"> s</span><span class="pun">,</span><span class="pln"> p</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> someMagicHere 
</span><span class="pun">})</span></pre>

<p>
	<strong>نصيحة للاحتراف 2</strong>: يمكنك استخدام <a href="https://marketplace.visualstudio.com/items?itemName=cmstead.jsrefactor" rel="external nofollow">إضافة للمحرر VS</a> يمكنها تحويل الدالة السهمية المختصرة إلى الكاملة وبالعكس.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="55235" href="https://academy.hsoub.com/uploads/monthly_2021_01/vs_plugin_007.png.029a4447af623c954ecf781efed6e398.png" rel=""><img alt="vs_plugin_007.png" class="ipsImage ipsImage_thumbnailed" data-fileid="55235" data-unique="d33gh7wqr" src="https://academy.hsoub.com/uploads/monthly_2021_01/vs_plugin_007.png.029a4447af623c954ecf781efed6e398.png"></a>
</p>

<h3>
	2.4: معلومات عن المنهاج: خطوة 9
</h3>

<p>
	وسّع التطبيق ليعمل مع أي عدد افتراضي من المناهج:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9974_83" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> courses </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
      name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Half Stack application development'</span><span class="pun">,</span><span class="pln">
      id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
      parts</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">
          name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Fundamentals of React'</span><span class="pun">,</span><span class="pln">
          exercises</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln">
          id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
        </span><span class="pun">},</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">
          name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Using props to pass data'</span><span class="pun">,</span><span class="pln">
          exercises</span><span class="pun">:</span><span class="pln"> </span><span class="lit">7</span><span class="pun">,</span><span class="pln">
          id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
        </span><span class="pun">},</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">
          name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'State of a component'</span><span class="pun">,</span><span class="pln">
          exercises</span><span class="pun">:</span><span class="pln"> </span><span class="lit">14</span><span class="pun">,</span><span class="pln">
          id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
        </span><span class="pun">},</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">
          name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Redux'</span><span class="pun">,</span><span class="pln">
          exercises</span><span class="pun">:</span><span class="pln"> </span><span class="lit">11</span><span class="pun">,</span><span class="pln">
          id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">]</span><span class="pln">
    </span><span class="pun">},</span><span class="pln"> 
    </span><span class="pun">{</span><span class="pln">
      name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Node.js'</span><span class="pun">,</span><span class="pln">
      id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln">
      parts</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">
          name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Routing'</span><span class="pun">,</span><span class="pln">
          exercises</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln">
          id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
        </span><span class="pun">},</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">
          name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Middlewares'</span><span class="pun">,</span><span class="pln">
          exercises</span><span class="pun">:</span><span class="pln"> </span><span class="lit">7</span><span class="pun">,</span><span class="pln">
          id</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">]</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">]</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="com">// ...</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يمكن أن يبدو التطبيق بالشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="55230" href="https://academy.hsoub.com/uploads/monthly_2021_01/app_course_extended_008.png.0df96f2a7926a18262af50413abf8654.png" rel=""><img alt="app_course_extended_008.png" class="ipsImage ipsImage_thumbnailed" data-fileid="55230" data-unique="lhhsfhm3s" src="https://academy.hsoub.com/uploads/monthly_2021_01/app_course_extended_008.png.0df96f2a7926a18262af50413abf8654.png"></a>
</p>

<h3>
	2.5 وحدات منفصلة
</h3>

<p>
	صرح عن المكوِّن <code>Course</code> في وحدة منفصلة يمكن إدراجها في ملف المكوِّن <code>App</code>. يمكن أن تضع كل المكوِّنات الفرعية للمنهاج ضمن نفس الوحدة.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://fullstackopen.com/en/part2/rendering_a_collection_modules" rel="external nofollow">Rendering a collection,modules</a> من سلسلة <a href="https://fullstackopen.com/en/" rel="external nofollow">Deep Dive Into Modern Web Development</a>
</p>
]]></description><guid isPermaLink="false">1094</guid><pubDate>Fri, 01 Jan 2021 13:00:00 +0000</pubDate></item><item><title>&#x62D;&#x627;&#x644;&#x627;&#x62A; &#x623;&#x639;&#x642;&#x62F; &#x644;&#x644;&#x645;&#x643;&#x648;&#x646;&#x627;&#x62A; &#x648;&#x62A;&#x646;&#x642;&#x64A;&#x62D; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; React</title><link>https://academy.hsoub.com/programming/javascript/react/%D8%AD%D8%A7%D9%84%D8%A7%D8%AA-%D8%A3%D8%B9%D9%82%D8%AF-%D9%84%D9%84%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-%D9%88%D8%AA%D9%86%D9%82%D9%8A%D8%AD-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-react-r1075/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_11/4.png.60368923fa1f20773f86319a2280ec61.png" /></p>

<h2>
	حالة أكثر تعقيدًا
</h2>

<p>
	كانت الحالة التي صادفتها في تطبيقنا السابق بسيطة لكونها متعلقة بعدد صحيح واحد. لكن ما العمل إن تطلب أحد التطبيقات التعامل مع حالة أكثر تعقيدًا؟ إنّ أكثر الطرق سهولة في إنجاز ذلك، هو استخدام دالة <code>useState</code> عدة مرات بحيث تتجزأ الحالة الكلية إلى "قطع" صغيرة. سنبني في الشيفرة التالية حالة من قطعتين لتطبيقنا تسمى الأولى "left" والأخرى "right" وستأخذ كل منهما 0 كقيمة ابتدائية.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_13" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">left</span><span class="pun">,</span><span class="pln"> setLeft</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">right</span><span class="pun">,</span><span class="pln"> setRight</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">left</span><span class="pun">}</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setLeft</span><span class="pun">(</span><span class="pln">left </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)}&gt;</span><span class="pln">
          left
        </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setRight</span><span class="pun">(</span><span class="pln">right </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)}&gt;</span><span class="pln">
          right
        </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">right</span><span class="pun">}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سنمنح المكوّن وصولًا إلى الدالتين <code>setLeft</code> و<code>setRight</code> اللتان ستُستخدمَان لتحديث قطعتي الحالة. يمكننا تحقيق غرض التطبيق بحفظ عدد النقرات التي تحصل على كلا الزرين "left" و"right" ضمن كائن مفرد:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_15" style="">
<span class="pun">{</span><span class="pln">
  left</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln">
  right</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وبهذا سيبدو التطبيق كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_17" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">clicks</span><span class="pun">,</span><span class="pln"> setClicks</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">({</span><span class="pln">
    left</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> right</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
  </span><span class="pun">})</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> handleLeftClick </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> newClicks </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
      left</span><span class="pun">:</span><span class="pln"> clicks</span><span class="pun">.</span><span class="pln">left </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> 
      right</span><span class="pun">:</span><span class="pln"> clicks</span><span class="pun">.</span><span class="pln">right 
    </span><span class="pun">}</span><span class="pln">
    setClicks</span><span class="pun">(</span><span class="pln">newClicks</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> handleRightClick </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> newClicks </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
      left</span><span class="pun">:</span><span class="pln"> clicks</span><span class="pun">.</span><span class="pln">left</span><span class="pun">,</span><span class="pln"> 
      right</span><span class="pun">:</span><span class="pln"> clicks</span><span class="pun">.</span><span class="pln">right </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> 
    </span><span class="pun">}</span><span class="pln">
    setClicks</span><span class="pun">(</span><span class="pln">newClicks</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">clicks</span><span class="pun">.</span><span class="pln">left</span><span class="pun">}</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">handleLeftClick</span><span class="pun">}&gt;</span><span class="pln">left</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">handleRightClick</span><span class="pun">}&gt;</span><span class="pln">right</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">clicks</span><span class="pun">.</span><span class="pln">right</span><span class="pun">}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يمتلك المكوّن الآن قطعة واحدة من الحالة، وستقع على عاتق معالجات الأحداث مهمة تغيير الحالة لكامل التطبيق. يبدو معالج الحدث فوضويًا بعض الشيء. فعندما يُنقر الزر "left" تُستدعى الدالة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_19" style="">
<span class="kwd">const</span><span class="pln"> handleLeftClick </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> newClicks </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
    left</span><span class="pun">:</span><span class="pln"> clicks</span><span class="pun">.</span><span class="pln">left </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> 
    right</span><span class="pun">:</span><span class="pln"> clicks</span><span class="pun">.</span><span class="pln">right 
  </span><span class="pun">}</span><span class="pln">
  setClicks</span><span class="pun">(</span><span class="pln">newClicks</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وتُخزّن القيم الجديدة لحالة التطبيق ضمن الكائن التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_21" style="">
<span class="pun">{</span><span class="pln">
  left</span><span class="pun">:</span><span class="pln"> clicks</span><span class="pun">.</span><span class="pln">left </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
  right</span><span class="pun">:</span><span class="pln"> clicks</span><span class="pun">.</span><span class="pln">right
</span><span class="pun">}</span></pre>

<p>
	ستحمل الخاصية <code>left</code> القيمة <code>left+1</code>، بينما ستبقى قيمة الخاصية <code>right</code> على ما كانت عليه في الحالة السابقة. يمكننا تعريف كائن الحالة الجديد بشكل أكثر أناقة مستخدمين صيغة توسيع الكائن (<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax" rel="external nofollow">object spread</a>) التي أضيفت إلى اللغة صيف 2018:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_23" style="">
<span class="kwd">const</span><span class="pln"> handleLeftClick </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> newClicks </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
    </span><span class="pun">...</span><span class="pln">clicks</span><span class="pun">,</span><span class="pln"> 
    left</span><span class="pun">:</span><span class="pln"> clicks</span><span class="pun">.</span><span class="pln">left </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> 
  </span><span class="pun">}</span><span class="pln">
  setClicks</span><span class="pun">(</span><span class="pln">newClicks</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> handleRightClick </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> newClicks </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
    </span><span class="pun">...</span><span class="pln">clicks</span><span class="pun">,</span><span class="pln"> 
    right</span><span class="pun">:</span><span class="pln"> clicks</span><span class="pun">.</span><span class="pln">right </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> 
  </span><span class="pun">}</span><span class="pln">
  setClicks</span><span class="pun">(</span><span class="pln">newClicks</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تبدو الصيغة غريبة بعض الشيء. حيث تنشئ العبارة <code>{clicks... }</code> كائنًا جديدًا يحمل نسخًا عن كل الخصائص التي يمتلكها الكائن <code>clicks</code>. فعندما نحدد خاصية معينة مثل <code>right</code> في العبارة <code>{clicks,right: 1...}</code>، ستكون القيمة الجديدة للخاصية <code>right</code> تساوي 1. لو تأملنا العبارة التالية في المثال السابق:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_25" style="">
<span class="pln"> </span><span class="pun">{...</span><span class="pln">clicks</span><span class="pun">,</span><span class="pln"> right</span><span class="pun">:</span><span class="pln"> clicks</span><span class="pun">.</span><span class="pln">right </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">}</span></pre>

<p>
	سنجد أنها تنشئ نسخًا للكائن <code>clicks</code>، ستزداد فيها قيم الخاصية <code>right</code> بمقدار واحد. لا حاجة إلى إسناد قيمة الخاصية إلى متغيّر في معالج الحدث وبالتالي سنبسط كتابة الدوال إلى الشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_27" style="">
<span class="kwd">const</span><span class="pln"> handleLeftClick </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln">
  setClicks</span><span class="pun">({</span><span class="pln"> </span><span class="pun">...</span><span class="pln">clicks</span><span class="pun">,</span><span class="pln"> left</span><span class="pun">:</span><span class="pln"> clicks</span><span class="pun">.</span><span class="pln">left </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">})</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> handleRightClick </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln">
  setClicks</span><span class="pun">({</span><span class="pln"> </span><span class="pun">...</span><span class="pln">clicks</span><span class="pun">,</span><span class="pln"> right</span><span class="pun">:</span><span class="pln"> clicks</span><span class="pun">.</span><span class="pln">right </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">})</span></pre>

<p>
	قد يتساءل بعض القراء لماذا لم نحدّث الحالة مباشرة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_29" style="">
<span class="kwd">const</span><span class="pln"> handleLeftClick </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  clicks</span><span class="pun">.</span><span class="pln">left</span><span class="pun">++</span><span class="pln">
  setClicks</span><span class="pun">(</span><span class="pln">clicks</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	فالتطبيق سيعمل أيضًا، لكن السبب أنّ React تمنع تغيير الحالة مباشرة، لأن ذلك قد يسبب أخطاء جانبية غير متوقعة. فالطريقة المعتمدة هي دائمًا إسناد الحالة إلى كائن جديد. إن لم يتغير الكائن الذي يضم الخصائص، فسُينسخ بكل بساطة إلى كائن جديد عن طريق نسخ خصائصه واعتماد الكائن الجديد ككائن للحالة. إنّ حفظ الحالة بكل قطعها في كائن واحد هو خيار سيئ في هذا التطبيق خصوصًا، فلن يقدّم الأمر أية فائدة وسيغدو التطبيق أكثر تعقيدًا. لذلك يفضل في حالات كهذه تقسيم الحالة إلى قطع أبسط. ستصادف حالات يكون فيها تخزين قطع من حالة التطبيق في بنًى أكثر تعقيدًا أمرًا مفيدًا، يمكنك الاطلاع على معلومات أكثر عن هذا الموضوع من خلال <a href="https://wiki.hsoub.com/React/hooks_faq#.D9.87.D9.84_.D9.8A.D8.AC.D8.A8_.D8.A3.D9.86_.D8.A7.D8.B3.D8.AA.D8.B9.D9.85.D9.84_.D9.85.D8.AA.D8.BA.D9.8A.D8.B1_.D8.AD.D8.A7.D9.84.D8.A9_.D9.88.D8.A7.D8.AD.D8.AF_.D8.A3.D9.85_.D8.B9.D8.AF.D8.A9_.D9.85.D8.AA.D8.BA.D9.8A.D8.B1.D8.A7.D8.AA.D8.9F" rel="external">التوثيق الرسمي لمكتبة React</a>.
</p>

<h2>
	التعامل مع المصفوفات Handling arrays
</h2>

<p>
	لنضف قطعة من الحالة إلى تطبيقنا. تتذكر المصفوفة <code>allClicks</code> كل نقرة على زر حدثت في التطبيق.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_31" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">left</span><span class="pun">,</span><span class="pln"> setLeft</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">right</span><span class="pun">,</span><span class="pln"> setRight</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">allClicks</span><span class="pun">,</span><span class="pln"> setAll</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">([])</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> handleLeftClick </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">    
    setAll</span><span class="pun">(</span><span class="pln">allClicks</span><span class="pun">.</span><span class="pln">concat</span><span class="pun">(</span><span class="str">'L'</span><span class="pun">))</span><span class="pln">
    setLeft</span><span class="pun">(</span><span class="pln">left </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> handleRightClick </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    setAll</span><span class="pun">(</span><span class="pln">allClicks</span><span class="pun">.</span><span class="pln">concat</span><span class="pun">(</span><span class="str">'R'</span><span class="pun">))</span><span class="pln">
    setRight</span><span class="pun">(</span><span class="pln">right </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">left</span><span class="pun">}</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">handleLeftClick</span><span class="pun">}&gt;</span><span class="pln">left</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">handleRightClick</span><span class="pun">}&gt;</span><span class="pln">right</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">right</span><span class="pun">}</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;{</span><span class="pln">allClicks</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="str">' '</span><span class="pun">)}&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ستُخزّن كل نقرة في القطعة <code>allClicks</code> والتي هُيِّئت على شكل مصفوفة فارغة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_33" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">allClicks</span><span class="pun">,</span><span class="pln"> setAll</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">([])</span></pre>

<p>
	سيُضاف الحرف 'L' إلى المصفوفة <code>allClicks</code> عندما يُنقر الزر "left":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_35" style="">
<span class="kwd">const</span><span class="pln"> handleLeftClick </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  setAll</span><span class="pun">(</span><span class="pln">allClicks</span><span class="pun">.</span><span class="pln">concat</span><span class="pun">(</span><span class="str">'L'</span><span class="pun">))</span><span class="pln">
  setLeft</span><span class="pun">(</span><span class="pln">left </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	إذًا فقطعة الحالة التي أنشأناها هي مصفوفة تضم كل عناصر الحالة السابقة بالإضافة إلى الحرف 'L'. وتتم إضافة العناصر الجديدة باستخدام التابع <a href="https://wiki.hsoub.com/JavaScript/Array/concat" rel="external">concat</a> الذي لا يعدل في المصفوفة، بل يعيد مصفوفةً جديدةً يضاف إليها العنصر الجديد. وكما ذكرنا سابقًا، يمكننا إضافة العناصر إلى مصفوفة باستخدام التابع <a href="https://wiki.hsoub.com/JavaScript/Array/push" rel="external">push</a>، حيث يمكن دفع العنصر داخل مصفوفة الحالة ثم تحديثها وسيعمل التطبيق:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_37" style="">
<span class="kwd">const</span><span class="pln"> handleLeftClick </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  allClicks</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="str">'L'</span><span class="pun">)</span><span class="pln">
  setAll</span><span class="pun">(</span><span class="pln">allClicks</span><span class="pun">)</span><span class="pln">
  setLeft</span><span class="pun">(</span><span class="pln">left </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لكن، لا تقم بذلك. فكما أشرنا سابقًا، لا يجب تغيير حالة مكوّنات React مثل <code>allClicks</code> مباشرةً. وحتى لو بدا الأمر ممكنًا، فقد يقودك إلى أخطاء من الصعب جدًا تنقيحها. لنلق الآن نظرة أقرب إلى الآلية التي يُصيّر بها التسلسل الزمني للنقرات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_49" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">left</span><span class="pun">}</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">handleLeftClick</span><span class="pun">}&gt;</span><span class="pln">left</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">handleRightClick</span><span class="pun">}&gt;</span><span class="pln">right</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">right</span><span class="pun">}</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;{</span><span class="pln">allClicks</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="str">' '</span><span class="pun">)}&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	استدعت الشيفرة السابقة التابع <a href="https://wiki.hsoub.com/JavaScript/Array/join" rel="external">join</a> الذي يجعل كل عناصر المصفوفة ضمن سلسلة نصية واحدة يفصل بينها فراغ وهو المعامل الذي مُرِّر إلى التابع.
</p>

<h2>
	التصيير الشرطي Conditional rendering
</h2>

<p>
	لنعدّل التطبيق بحيث يتولى الكائن الجديد <code>History</code> أمر تصيير تاريخ النقر على الأزرار:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_41" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">History</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">.</span><span class="pln">allClicks</span><span class="pun">.</span><span class="pln">length </span><span class="pun">===</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        the app is used by pressing the buttons
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      button press history</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">allClicks</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="str">' '</span><span class="pun">)}</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">left</span><span class="pun">}</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">handleLeftClick</span><span class="pun">}&gt;</span><span class="pln">left</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">handleRightClick</span><span class="pun">}&gt;</span><span class="pln">right</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">right</span><span class="pun">}</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">History</span><span class="pln"> allClicks</span><span class="pun">={</span><span class="pln">allClicks</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيعتمد الآن سلوك التطبيق على أحداث النقر على الأزرار. إن لم تُنقر أية أزرار، سيعني ذلك أن مصفوفة الحالة <code>allClicks</code> فارغة. سيُصيّر عندها المكوّن العنصر <code>div</code> وقد ظهرت ضمنه تعليمات للمستخدم:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_43" style="">
<span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">the app is used by pressing the buttons</span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
</span><span class="com">//..يستخدم التطبيق بالنقر على الأزرار</span></pre>

<p>
	بقية الحالات سيصيّر المكوّن تاريخ النقر على الأزرار:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_45" style="">
<span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  button press history</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">allClicks</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="str">' '</span><span class="pun">)}</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span></pre>

<p>
	يصيّر المكوّن <code>History</code> مكوّنات React مختلفةً كليًا وفقًا لحالة التطبيق. يدعى هذا بالتصيير الشرطي. تقدم React طرقًا عدة <a href="https://wiki.hsoub.com/React/conditional_rendering" rel="external">للتصيير الشرطي</a> والتي سنلقي عليها نظرةً أقرب في القسم 2 لاحقًا من <a href="https://academy.hsoub.com/tags/full_stack_101/" rel="">هذه السلسلة</a>. سنجري تعديلًا أخيرًا على تطبيقنا بإعادة صياغته مستخدمين المكوّن <code>Button</code> الذي عرّفناه سابقًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_47" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">History</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">.</span><span class="pln">allClicks</span><span class="pun">.</span><span class="pln">length </span><span class="pun">===</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        the app is used by pressing the buttons
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      button press history</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">allClicks</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="str">' '</span><span class="pun">)}</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Button</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> onClick</span><span class="pun">,</span><span class="pln"> text </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">  
  </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">onClick</span><span class="pun">}&gt;</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">text</span><span class="pun">}</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">left</span><span class="pun">,</span><span class="pln"> setLeft</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">right</span><span class="pun">,</span><span class="pln"> setRight</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">allClicks</span><span class="pun">,</span><span class="pln"> setAll</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">([])</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> handleLeftClick </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    setAll</span><span class="pun">(</span><span class="pln">allClicks</span><span class="pun">.</span><span class="pln">concat</span><span class="pun">(</span><span class="str">'L'</span><span class="pun">))</span><span class="pln">
    setLeft</span><span class="pun">(</span><span class="pln">left </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> handleRightClick </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    setAll</span><span class="pun">(</span><span class="pln">allClicks</span><span class="pun">.</span><span class="pln">concat</span><span class="pun">(</span><span class="str">'R'</span><span class="pun">))</span><span class="pln">
    setRight</span><span class="pun">(</span><span class="pln">right </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">left</span><span class="pun">}</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">Button</span><span class="pln"> onClick</span><span class="pun">={</span><span class="pln">handleLeftClick</span><span class="pun">}</span><span class="pln"> text</span><span class="pun">=</span><span class="str">'left'</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">Button</span><span class="pln"> onClick</span><span class="pun">={</span><span class="pln">handleRightClick</span><span class="pun">}</span><span class="pln"> text</span><span class="pun">=</span><span class="str">'right'</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">right</span><span class="pun">}</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">History</span><span class="pln"> allClicks</span><span class="pun">={</span><span class="pln">allClicks</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	كلمة حول React القديمة
</h2>

<p>
	نستخدم في هذا المنهاج <a href="https://wiki.hsoub.com/React/hooks_state" rel="external">state hook</a> لإضافة حالة إلى مكوّنات React، حيث تعتبر الخطافات جزءًا من نسخ React الأحدث وتتوفر ابتداء من النسخة 16.8.0. لم تكن هناك طرق لإضافة حالة إلى دالة المكوّن قبل إضافة الخطافات، حيث عُرّفت المكوّنات التي تحتاج إلى حالة كصفوف <a href="https://wiki.hsoub.com/React/react_component" rel="external">class</a> باستخدام الصيغة <code>class</code>. لقد قررنا في هذا المنهاج استخدام الخطافات منذ البداية لكي نضمن أننا نتعلم الأسلوب المستقبلي لمكتبة React. وعلى الرغم من أن المكوّنات المبنية على شكل دوال هي مستقبل React، لا يزال تعلم استخدام الأصناف مهمًا. فهناك المليارات من سطور الشيفرة المكتوبة بالأسلوب القديم، وقد ينتهي بك الأمر يومًا وأنت تنقح أحدها، أو قد تتعامل مع توثيق أو أمثلة عن React القديمة على الإنترنت. إذًا سنتعلم أكثر عن الأصناف لكن ليس الآن.
</p>

<h2>
	تنقيح تطبيقات React
</h2>

<p>
	يمضي المطورون وقتًا طويلًا في تنقيح وتصيير الشيفرات الموجودة، ويتوجب عليهم بين الفينة والأخرى كتابة أسطر جديدة. لكن بطبيعة الحال سنقضي جُلّ وقتنا باحثين عن سبب خطأ ما أو عن الطريقة التي يعمل بها مكوّن ما. لذلك فاقتناء أدوات للتنقيح والتمكّن من تحري الأخطاء أمر مهم للغاية. ولحسن الحظ تقدم مكتبة React عونًا منقطع النظير للمطورين فيما يتعلق بموضوع التنقيح. قبل أن نتابع، دعونا نتذكر القاعدة الأكثر أهمية في تطوير الويب، حيث تنص <strong>القاعدة الأولى في تطوير الويب</strong> على مايلي:
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p>
		ابق طرفية التطوير الخاصة بمتصفحك مفتوحةً دائمًا. افتح دائمًا النافذة <em>Console</em> ودعها مفتوحة، إن لم يكن هناك سبب لفتح نافذة أخرى.
	</p>
</blockquote>

<p>
	وعليك أن تبقي المحرر الذي تكتب فيه الشيفرة مفتوحًا في نفس الوقت مع صفحة الويب ودائمًا. وتذكر عندما تُخفق الشيفرة ويمتلئ المتصفح بالأخطاء أن لا تكتب المزيد من الشيفرة بل ابحث عن الخطأ وصححه مباشرةً.
</p>

<p style="text-align: center;">
	<img alt="fail_to_compile_01.png" class="ipsImage ipsImage_thumbnailed" data-fileid="53799" data-unique="rqoe4jkdl" src="https://academy.hsoub.com/uploads/monthly_2020_11/fail_to_compile_01.png.7fc33ed2b9fbfe47bc3fbab5717129a9.png"></p>

<p>
	لقد مر زمن كان فيه كتابة المزيد من الشيفرة تمثل حلًا سحريًا للأخطاء، لكننا نجزم أن شيئًا كهذا لن يحدث في هذا المنهاج. لا تزال الطريقة القديمة في التنقيح والتي تعتمد على طباعة القيم على الطرفية فكرة جيدة.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_51" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Button</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> onClick</span><span class="pun">,</span><span class="pln"> text </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">onClick</span><span class="pun">}&gt;</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">text</span><span class="pun">}</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">)</span></pre>

<p>
	إن لم يعمل المكوّن كما يفترض، اطبع قيم متغيراته على الطرفية. ولكي تنفذ ذلك بشكل فعّال، عليك تحويل الدوال إلى شكلٍ أقل اختصارًا وأن تستقبل قيم جميع الخصائص دون أن تفككها مباشرةً.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_53" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Button</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln">  
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> onClick</span><span class="pun">,</span><span class="pln"> text </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> props
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">onClick</span><span class="pun">}&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">text</span><span class="pun">}</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيكشف ذلك مباشرة أنّ اسم إحدى الخصائص مثلًا قد كُتب بطريقة خاطئة عند استخدام المكوّن.
</p>

<p>
	<strong>ملاحظة</strong>: عندما تستخدم التعليمة <code>console.log</code> للتنقيح، لا تستخدم أسلوبًا مشابهًا لشيفرة Java. فلو أردت ضم معلومات مختلفة في الرسالة مثل استخدام إشارة (+). لا تكتب:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_55" style="">
<span class="pln">console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'props value is '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> props</span><span class="pun">)</span></pre>

<p>
	بل افصل بين الأشياء التي تريد طباعتها بفاصلة ",":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_57" style="">
<span class="pln">console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'props value is'</span><span class="pun">,</span><span class="pln"> props</span><span class="pun">)</span></pre>

<p>
	فعندما تستخدم طريقة مشابهة لطريقة Java بضم سلسلة نصية إلى كائن سينتهي الأمر بالحصول على رسالة غير مفهومة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_59" style="">
<span class="pln">props value is </span><span class="pun">[</span><span class="typ">Object</span><span class="pln"> object</span><span class="pun">]</span></pre>

<p>
	بينما ستبقى العناصر التي تفصل بينها باستخدام الفاصلة واضحة على طرفية المتصفح. لا تُعتبر طريقة الولوج إلى الطرفية على أية حال هي الطريقة الوحيدة لتنقيح التطبيقات. إذ يمكنك إيقاف تنفيذ الشيفرة في منقح طرفية التطوير لمتصفح Chrome مثلًا باستخدام الأمر <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger" rel="external nofollow">debugger</a> في أي مكان ضمن الشيفرة. حيث سيتوقف التنفيذ عندما تصل إلى النقطة التي وضعت فيها الأمر السابق:
</p>

<p style="text-align: center;">
	<img alt="using_debugger_command_02.png" class="ipsImage ipsImage_thumbnailed" data-fileid="53809" data-unique="6eyf0t684" src="https://academy.hsoub.com/uploads/monthly_2020_11/using_debugger_command_02.png.21fae3600c2052dc66a337c9f1f7b5f6.png"></p>

<p>
	انتقل إلى النافذة Console لتتابع الحالة الراهنة للمتغيّرات بسهولة:
</p>

<p style="text-align: center;">
	<img alt="using_console_tab_03.png" class="ipsImage ipsImage_thumbnailed" data-fileid="53808" data-unique="lxtj5u2i4" src="https://academy.hsoub.com/uploads/monthly_2020_11/using_console_tab_03.png.00217b237c8dd2911101b502e23ab20a.png"></p>

<p>
	يمكنك إزالة الأمر <code>debugger</code> وإعادة تحميل الصفحة حالما تكتشف الخطأ في شيفرتك. يمكّنك المنقح أيضًا من تنفيذ الشيفرة سطرًا سطرًا باستخدام عناصر التحكم الخاصة الموجودة على يمين النافذة source في الطرفية. لا حاجة لاستخدام الأمر <code>debugger</code> للوصول إلى المنقح، يمكنك عوضًا عن ذلك استخدام نقاط التوقف (break point) الموجودة في النافذة source، وتتبّع قيم متغيرات المكوّن في القسم Scope:
</p>

<p style="text-align: center;">
	<img alt="console_source_window_04.png" class="ipsImage ipsImage_thumbnailed" data-fileid="53798" data-unique="amwtiatcf" src="https://academy.hsoub.com/uploads/monthly_2020_11/console_source_window_04.png.9216adebafe7efa42a9cfaec884670c1.png"></p>

<p>
	ننصحك بشدة أن تضيف إضافة مُوسِّعة (extension) لمكتبة React على متصفح Chrome تدعى <a href="https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi" rel="external nofollow">React developer tools</a>، الذي سيضيف النافذة الجديدة React إلى الطرفية:
</p>

<p style="text-align: center;">
	<img alt="react_extension_05.png" class="ipsImage ipsImage_thumbnailed" data-fileid="53801" data-unique="z619mvdr9" src="https://academy.hsoub.com/uploads/monthly_2020_11/react_extension_05.png.2957db3751ccc85178970875d671633c.png"></p>

<p>
	سنستخدم أدوات تطوير React الجديدة في تتبع حالة العناصر المختلفة في التطبيق وخصائصها. لكن النسخة الحالية من هذا الموسِّع تُغفل عرض المطلوب عن حالة المكوّنات التي تنشئها الخطافات:
</p>

<p style="text-align: center;">
	<img alt="react_extension_hooks_06.png" class="ipsImage ipsImage_thumbnailed" data-fileid="53802" data-unique="5hazq3n3b" src="https://academy.hsoub.com/uploads/monthly_2020_11/react_extension_hooks_06.png.d7f10052381de50c12b8178ff24fa451.png"></p>

<p>
	عُرّفت حالة المكوّن بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_61" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">left</span><span class="pun">,</span><span class="pln"> setLeft</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">right</span><span class="pun">,</span><span class="pln"> setRight</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">allClicks</span><span class="pun">,</span><span class="pln"> setAll</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">([])</span></pre>

<p>
	تُظهر أدوات التطوير حالة الخطافات حسب تسلسل تعريفها:
</p>

<p style="text-align: center;">
	<img alt="hooks_state_order_07.png" class="ipsImage ipsImage_thumbnailed" data-fileid="53800" data-unique="w4tn1vtd4" src="https://academy.hsoub.com/uploads/monthly_2020_11/hooks_state_order_07.png.289cbc6de1d34cfd0255a6fe36b72bed.png"></p>

<h2>
	قواعد استخدام الخطافات Rules of Hooks
</h2>

<p>
	هناك قواعد وحدود معينة يجب أن نتقيد بها لنتأكد أن الحالة التي تعتمد على الخطافات في التطبيق ستعمل كما يجب. فلا يجب استدعاء التابع <code>useState</code> (وكذلك التابع <code>useEffect</code> الذي سنتعرف عليه لاحقًا) من داخل الحلقات أو العبارت الشرطية أو من أي موقع لا يمثل دالة لتعريف مكوّن. ذلك لنضمن أن الخطافات ستُستدعى وفق الترتيب ذاته لتعريفها وإلا سيتصرف التطبيق بشكل فوضوي. باختصار <strong>استدع الخطافات من داخل جسم الدوال المعرِّفة للمكوّنات</strong>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_63" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// الشيفرة التالية صحيحة</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">age</span><span class="pun">,</span><span class="pln"> setAge</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> setName</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="str">'Juha Tauriainen'</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> age </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">10</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// هذه الشيفرة لن تعمل</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">foobar</span><span class="pun">,</span><span class="pln"> setFoobar</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="kwd">null</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> let i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> age</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// هذه غير جيدة أيضًا</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">rightWay</span><span class="pun">,</span><span class="pln"> setRightWay</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="kwd">false</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> notGood </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// هذه غير مشروعة</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> setX</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(-</span><span class="lit">1000</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="com">//...</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	عودة إلى معالجة الأحداث
</h2>

<p>
	أثبت موضوع معالجة الأحداث صعوبته ضمن الأفكار المتسلسلة التي قدمناها حتى الآن، لذلك سنعود إليه مجددًا. لنفترض أننا نطور هذا التطبيق البسيط:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_65" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">value</span><span class="pun">,</span><span class="pln"> setValue</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">10</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">value</span><span class="pun">}</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">reset to zero</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="typ">ReactDOM</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="typ">App</span><span class="pln"> </span><span class="pun">/&gt;,</span><span class="pln"> 
  document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'root'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">)</span></pre>

<p>
	المطلوب هو النقر على الزر لتصفير الحالة المخزّنة ضمن المتغّير <code>value</code>. علينا إضافة معالج حدث للزر لكي يتفاعل مع حدث النقر عليه. تذكر أن معالجات الأحداث يجب أن تكون دائمًا دوال أو مراجع لدوال. لن يعمل الزر إذا أسند معالج الحدث إلى متغيّر من أي نوع آخر. فلو عرفنا معالج الحدث على شكل نص كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_67" style="">
<span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="str">'crap...'</span><span class="pun">}&gt;</span><span class="pln">button</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span></pre>

<p>
	ستحذرنا React من ذلك على الطرفية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_69" style="">
<span class="pln">index</span><span class="pun">.</span><span class="pln">js</span><span class="pun">:</span><span class="lit">2178</span><span class="pln"> </span><span class="typ">Warning</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Expected</span><span class="pln"> </span><span class="pun">`</span><span class="pln">onClick</span><span class="pun">`</span><span class="pln"> listener to be a </span><span class="kwd">function</span><span class="pun">,</span><span class="pln"> instead got a value of </span><span class="pun">`</span><span class="pln">string</span><span class="pun">`</span><span class="pln"> type</span><span class="pun">.</span><span class="pln">
    in button </span><span class="pun">(</span><span class="pln">at index</span><span class="pun">.</span><span class="pln">js</span><span class="pun">:</span><span class="lit">20</span><span class="pun">)</span><span class="pln">
    in div </span><span class="pun">(</span><span class="pln">at index</span><span class="pun">.</span><span class="pln">js</span><span class="pun">:</span><span class="lit">18</span><span class="pun">)</span><span class="pln">
    in </span><span class="typ">App</span><span class="pln"> </span><span class="pun">(</span><span class="pln">at index</span><span class="pun">.</span><span class="pln">js</span><span class="pun">:</span><span class="lit">27</span><span class="pun">)</span></pre>

<p>
	وكذلك لن يعمل المعالج التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_71" style="">
<span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">value </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">}&gt;</span><span class="pln">button</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span></pre>

<p>
	حيث نعرف معالج الحدث في هذه الحالة بالعبارة <code>value+1</code> التي ستعيد قيمة العملية، وستحذرنا React أيضًا:
</p>

<pre class="ipsCode">
index.js:2178 Warning: Expected `onClick` listener to be a function, instead got a value of `number` type.
</pre>

<p>
	هذه الطريقة لن تنفع أيضًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_73" style="">
<span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">}&gt;</span><span class="pln">button</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span></pre>

<p>
	فمعالج الحدث هنا لا يمثل دالة بل عملية إسناد لمتغيّر، وستحذرنا React مجددًا على الطرفية. وتعتبر هذه العملية خاطئة أيضًا من مبدأ عدم تغيير الحالة بشكل مباشر. لكن ماذا لو فعلنا التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_75" style="">
<span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'clicked the button'</span><span class="pun">)}&gt;</span><span class="pln">
  button
</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span></pre>

<p>
	ستُطبع العبارة المكتوبة داخل الدالة لمرة واحدة ولن يحدث بعدها شيء عند إعادة نقر الزر. لماذا لم يعمل معالج الحدث إذًا على الرغم من وجود الدالة <code>console.log</code>؟ المشكلة هنا أن معالج الحدث قد عُرّف كاستدعاء لدالة، أي أنه سيعيد قيمة الدالة والتي ستكون "غير محددة" في حالة <code>console.log</code>. ستُنفَّذ هذه الدالة تحديدًا عندما يُعاد تصيير المكوّن، ولهذا لم تظهر العبارة سوى مرة واحدة. ستخفق المحاولة التالية أيضًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_77" style="">
<span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">setValue</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)}&gt;</span><span class="pln">button</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span></pre>

<p>
	ستجعل معالج الحدث استدعاءً لدالة أيضًا في هذه المحاولة، لن يفلح ذلك. ستسبب هذه المحاولة تحديدًا مشكلة من نوع آخر. فعندما يُصيّر المكوّن، ستُنفَّذ الدالة <code>(setvalue(0</code> والتي بدورها ستُعيد تصيير المكوّن. إعادة التصيير هذه تستدعي مجددًا <code>(setvalue(0</code> وهذا ما يسبب حلقة لانهائية من الاستدعاءات. تُستدعى دالة محددة عند النقر على الزر كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_79" style="">
<span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'clicked the button'</span><span class="pun">)}&gt;</span><span class="pln">
  button
</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span></pre>

<p>
	يمثل معالج الحدث الآن دالة معرفة بالطريقة السهمية <code>(console.log('clicked the button &lt;= ()</code>. فلن تُستدعى الآن أية دوال عندما يصيّر المكوّن، لأن معالج الحدث قد أسند إلى مرجع لدالة سهمية، ولن تُستدعى هذه الدالة إلا بعد النقر على الزر. يمكننا استخدام نفس الأسلوب لإضافة زر تصفير الحالة في التطبيق الذي بدأناه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_81" style="">
<span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setValue</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)}&gt;</span><span class="pln">button</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span></pre>

<p>
	لقد جعلت الشيفرة السابقة الدالة <code>(setValue(0 &lt;=()</code> معالج الحدث للزر. لا يعتبر تعريف معالج الحدث مباشرة ضمن الخاصية <code>onClick</code> الطريقة الأفضل بالضرورة. حيث نجده أحيانًا معرفًا في مكان آخر. سنعرّف في النسخة التالية من التطبيق الدالة السهمية التي ستلعب دور معالج الحدث ضمن جسم المكوّن ومن ثم سنسندها إلى المتغيّر <code>handleClick</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_83" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">value</span><span class="pun">,</span><span class="pln"> setValue</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">10</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> handleClick </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'clicked the button'</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">value</span><span class="pun">}</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">handleClick</span><span class="pun">}&gt;</span><span class="pln">button</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يعتبر المتغيّر <code>handleClick</code> مرجعًا للدالة السهمية، وسيُمرَّر هذا المرجع إلى الزر كقيمة للخاصية <code>onClick</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_85" style="">
<span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">handleClick</span><span class="pun">}&gt;</span><span class="pln">button</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span></pre>

<p>
	قد تضم دالة معالج الحدث أكثر من أمر، فلا بد عندها من وضع الأوامر بين قوسين معقوصين:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_87" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">value</span><span class="pun">,</span><span class="pln"> setValue</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">10</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> handleClick </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'clicked the button'</span><span class="pun">)</span><span class="pln">
      setValue</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">value</span><span class="pun">}</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">handleClick</span><span class="pun">}&gt;</span><span class="pln">button</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
    v</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	الدالة التي تعيد دالة
</h2>

<p>
	يمكن تعريف معالج حدث بطريقة الدالة التي تعيد دالة. وقد لا تضطر إلى استخدام هذا النوع من الدوال في هذا المنهاج. إن بدا لك الأمر مربكًا بعض الشيء تجاوز هذا المقطع الآن وعد إليه لاحقًا. لنعدل الشيفرة لتصبح كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_91" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">value</span><span class="pun">,</span><span class="pln"> setValue</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">10</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> hello </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> handler </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'hello world'</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> handler
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">value</span><span class="pun">}</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">hello</span><span class="pun">()}&gt;</span><span class="pln">button</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ستعمل هذه الشيفرة بشكل صحيح على الرغم من مظهرها المعقد. يستدعي معالج الحدث هنا دالة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_93" style="">
<span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">hello</span><span class="pun">()}&gt;</span><span class="pln">button</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span></pre>

<p>
	لكننا قررنا سابقًا أن لا يكون معالج الحدث استدعاء لدالة، بل يجب أن يكون دالة أو مرجعًا لها. لماذا إذًا سيعمل المعالج في هذه الحالة؟ عندما يُصيّر المكوّن، ستُنفّذ الدالة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_95" style="">
<span class="kwd">const</span><span class="pln"> hello </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> handler </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'hello world'</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> handler
</span><span class="pun">}</span></pre>

<p>
	إنّ القيمة المعادة من الدالة السهمية الأولى هي دالة سهمية أخرى أسندت إلى المتغيّر <code>handler</code>. فعندما تصيّر React السطر التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_97" style="">
<span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">hello</span><span class="pun">()}&gt;</span><span class="pln">button</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span></pre>

<p>
	ستُسنَد القيمة المعادة من <code>()hello</code> إلى الخاصية <code>onClick</code>، وسيتحول السطر مبدئيًا إلى:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5307_99" style="">
<span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'hello world'</span><span class="pun">)}&gt;</span><span class="pln">
  button
</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span></pre>

<p>
	إذًا نجح الأمر لأن الدالة <code>hello</code> قد أعادت دالة وسيكون معالج الحدث دالة أيضًا. لكن ما المغزى من هذا المبدأ؟ لنغير الشيفرة قليلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_101" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">value</span><span class="pun">,</span><span class="pln"> setValue</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">10</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> hello </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">who</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> handler </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'hello'</span><span class="pun">,</span><span class="pln"> who</span><span class="pun">)</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> handler
</span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">value</span><span class="pun">}</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">hello</span><span class="pun">(</span><span class="str">'world'</span><span class="pun">)}&gt;</span><span class="pln">button</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">hello</span><span class="pun">(</span><span class="str">'react'</span><span class="pun">)}&gt;</span><span class="pln">button</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">hello</span><span class="pun">(</span><span class="str">'function'</span><span class="pun">)}&gt;</span><span class="pln">button</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يضم التطبيق الآن ثلاثة أزرار لكل منها معالج حدث تُعرّفه الدالة <code>hello</code> التي تقبل معاملًا. عُرّف الزر الأول كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_103" style="">
<span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">hello</span><span class="pun">(</span><span class="str">'world'</span><span class="pun">)}&gt;</span><span class="pln">button</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span></pre>

<p>
	يٌنشأ معالج الحدث باستدعاء الدالة <code>hello</code> التي تعيد الدالة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_105" style="">
<span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'hello'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'world'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يُعرّف الزر التالي بالشكل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_107" style="">
<span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">hello</span><span class="pun">(</span><span class="str">'react'</span><span class="pun">)}&gt;</span><span class="pln">button</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span></pre>

<p>
	سيعيد استدعاء الدالة <code>(hello(react</code> (التي تُنشئ معالج الحدث الخاص بالزر) مايلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_109" style="">
<span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'hello'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'react'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لاحظ أن كلا الزرين حصل على معالج حدث خاص به. فاستخدام الدوال التي تعيد دوال قد يساعد على تعريف الدوال المعمّمة التي يمكن تغييرها حسب الطلب باستخدام المعاملات. حيث تمثل الدالة <code>hello</code> التي أنشأت معالجات الأحداث مصنعًا لإنتاج معالجات أحداث يحددها المستخدم كما يشاء. يبدو تعريف الدالة التالي طويلًا نوعا ما:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_111" style="">
<span class="kwd">const</span><span class="pln"> hello </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">who</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> handler </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'hello'</span><span class="pun">,</span><span class="pln"> who</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> handler
</span><span class="pun">}</span></pre>

<p>
	لنحذف متغيّرات الدالة المساعدة ونعيد التابع الذي أنشأناه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_113" style="">
<span class="kwd">const</span><span class="pln"> hello </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">who</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'hello'</span><span class="pun">,</span><span class="pln"> who</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وطالما أن الدالة <code>hello</code> مؤلفة من عبارة برمجية واحدة، سنحذف القوسين المعقوصين أيضًا ونستخدم الشكل المختصر للدالة السهمية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_115" style="">
<span class="kwd">const</span><span class="pln"> hello </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">who</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln">
  </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'hello'</span><span class="pun">,</span><span class="pln"> who</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span></pre>

<p>
	أخيرًا لنكتب كل الأسهم على السطر نفسه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_117" style="">
<span class="kwd">const</span><span class="pln"> hello </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">who</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'hello'</span><span class="pun">,</span><span class="pln"> who</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يمكننا استخدام الحيلة ذاتها لتعريف معالجات الأحداث لإسناد قيمة معينة إلى حالة المكوّن، لنغيّر الشيفرة كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_119" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">value</span><span class="pun">,</span><span class="pln"> setValue</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">10</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> setToValue </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">newValue</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    setValue</span><span class="pun">(</span><span class="pln">newValue</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">  
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">value</span><span class="pun">}</span><span class="pln">
       </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">setToValue</span><span class="pun">(</span><span class="lit">1000</span><span class="pun">)}&gt;</span><span class="pln">thousand</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">setToValue</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)}&gt;</span><span class="pln">reset</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
     </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">setToValue</span><span class="pun">(</span><span class="pln">value </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)}&gt;</span><span class="pln">increment</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	عندما يُصيّر المكوّن، سيُنشأ الزر <code>thousand</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_121" style="">
<span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">setToValue</span><span class="pun">(</span><span class="lit">1000</span><span class="pun">)}&gt;</span><span class="pln">thousand</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span></pre>

<p>
	يضبط معالج الحدث ليعيد قيمة العبارة <code>(setValue(1000</code>، والتي تمثلها الدالة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_123" style="">
<span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  setValue</span><span class="pun">(</span><span class="lit">1000</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يُعرّف زر الزيادة بالطريقة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_125" style="">
<span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">setToValue</span><span class="pun">(</span><span class="pln">value </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)}&gt;</span><span class="pln">increment</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span></pre>

<p>
	يُنشأ معالج الحدث باستدعاء الدالة <code>(setToValue(value + 1</code> والتي تستقبل قيمة متغير الحالة <code>value</code> كمعامل لها بعد زيادته بواحد. فلو كانت قيمة المتغير 10 سيكون معالج الحدث الذي سيُنشأ كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_127" style="">
<span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  setValue</span><span class="pun">(</span><span class="lit">11</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لبس ضروريًا استخدام (دوال تعيد دوال) لتقديم وظائف كهذه، فلو أعدنا الدالة <code>setToValue</code> المسؤولة عن تحديث الحالة إلى دالة عادية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_129" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">value</span><span class="pun">,</span><span class="pln"> setValue</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">10</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> setToValue </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">newValue</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    setValue</span><span class="pun">(</span><span class="pln">newValue</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">value</span><span class="pun">}</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setToValue</span><span class="pun">(</span><span class="lit">1000</span><span class="pun">)}&gt;</span><span class="pln">
        thousand
      </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setToValue</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)}&gt;</span><span class="pln">
        reset
      </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setToValue</span><span class="pun">(</span><span class="pln">value </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)}&gt;</span><span class="pln">
        increment
      </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يمكننا عندها تعريف معالج الحدث كدالة تستدعي الدالة <code>setToValue</code> باستخدام المعامل المناسب. وسيكون عندها معالج الحدث لتصفير الحالة من الشكل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_131" style="">
<span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setToValue</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)}&gt;</span><span class="pln">reset</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span></pre>

<p>
	وفي النهاية اختيار أي من الطريقتين السابقتين في تعريف معالج الحدث هو أمر شخصي.
</p>

<h2>
	تمرير معالجات الأحداث إلى المكوّنات الأبناء
</h2>

<p>
	لنجزِّء مكوّن الزر إلى أقسامه الرئيسية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5307_133" style="">
<span class="pln">const Button = (props) =&gt; (
  </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">onClick</span><span class="pun">={</span><span class="pln">props</span><span class="pun">.</span><span class="pln">handleClick</span><span class="pun">}</span><span class="tag">&gt;</span><span class="pln">
    {props.text}
  </span><span class="tag">&lt;/button&gt;</span><span class="pln">
)</span></pre>

<p>
	يحصل المكوّن على دالة معالج الحدث الخاصة به من الخاصية <code>handleClick</code> ويأخذ النص الذي سيظهر عليه من الخاصية <code>text</code>. إنّ استخدام المكوّن <code>Button</code> أمر سهل، لكن علينا التأكد من اسم الصفة قبل تمرير الخاصية إلى المكوّن.
</p>

<p style="text-align: center;">
	<img alt="button_component_08.png" class="ipsImage ipsImage_thumbnailed" data-fileid="53797" data-unique="jhpx4n63k" src="https://academy.hsoub.com/uploads/monthly_2020_11/button_component_08.png.c6a00587e09998111fc2a1c3c1cc7784.png"></p>

<h2>
	لا تعرّف المكوّنات داخل المكوّنات
</h2>

<p>
	لنبدأ بإظهار قيمة التطبيق ضمن المكوّن <code>Display</code> الخاص به. سنعدل الشيفرة بتعريف مكوّن جديد داخل المكوّن <code>App</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_135" style="">
<span class="com">// هذا هو المكان الصحيح لتعريف المكون</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Button</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">props</span><span class="pun">.</span><span class="pln">handleClick</span><span class="pun">}&gt;</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">text</span><span class="pun">}</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> props </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">value</span><span class="pun">,</span><span class="pln"> setValue</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">10</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> setToValue </span><span class="pun">=</span><span class="pln"> newValue </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    setValue</span><span class="pun">(</span><span class="pln">newValue</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="com">// لا تعرف المكونات داخل المكونات</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Display</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> props </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">value</span><span class="pun">}&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Display</span><span class="pln"> value</span><span class="pun">={</span><span class="pln">value</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Button</span><span class="pln"> handleClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setToValue</span><span class="pun">(</span><span class="lit">1000</span><span class="pun">)}</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"thousand"</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Button</span><span class="pln"> handleClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setToValue</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)}</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"reset"</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Button</span><span class="pln"> handleClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setToValue</span><span class="pun">(</span><span class="pln">value </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)}</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"increment"</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيعمل التطبيق كما يبدو، لكن <strong>لا تعرّف مكوّنًا ضمن آخر</strong>. لن يقدم لك ذلك أية فائدة وسيقود إلى مشاكل عديدة. إذًا دعونا ننقل المكوّن <code>Display</code> إلى مكانه الصحيح خارج دالة المكوّن <code>App</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_137" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Display</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> props </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">value</span><span class="pun">}&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Button</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">props</span><span class="pun">.</span><span class="pln">handleClick</span><span class="pun">}&gt;</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">text</span><span class="pun">}</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> props </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">value</span><span class="pun">,</span><span class="pln"> setValue</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">10</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> setToValue </span><span class="pun">=</span><span class="pln"> newValue </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    setValue</span><span class="pun">(</span><span class="pln">newValue</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Display</span><span class="pln"> value</span><span class="pun">={</span><span class="pln">value</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Button</span><span class="pln"> handleClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setToValue</span><span class="pun">(</span><span class="lit">1000</span><span class="pun">)}</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"thousand"</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Button</span><span class="pln"> handleClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setToValue</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)}</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"reset"</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Button</span><span class="pln"> handleClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setToValue</span><span class="pun">(</span><span class="pln">value </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)}</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"increment"</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	مواد جديرة بالقراءة
</h2>

<p>
	تمتلئ شبكة الإنترنت بمواد متعلقة بمكتبة React. لكننا في هذا المنهاج سنستخدم الأسلوب الجديد. ستجد غالبية المواد المتوفرة أقدم مما نبغي، لكن ربما ستجد الروابط التالية مفيدة:
</p>

<ul>
<li>
		<a href="https://academy.hsoub.com/programming/javascript/react" rel="">دروس ومقالات حول React من أكاديمية حسوب</a>
	</li>
	<li>
		<a href="https://wiki.hsoub.com/React" rel="external">توثيقات React الرسمية</a>: تستحق هذه التوثيقات المطالعة في مرحلة ما، حيث يغدو لمعظم محتوياتها أهمية في سياق المنهاج، ماعدا تلك المتعلقة بالمكوّنات المعتمدة على الأصناف.
	</li>
	<li>
		بعض مناهج <a href="https://egghead.io/" rel="external nofollow">Egghead.io</a> الأجنبية: مثل <a href="https://egghead.io/courses/start-learning-react" rel="external nofollow">Start learning React</a> وتتمتع بقيمة عالية، وقد جرى تحديثها مؤخرًا. ويعتبر كذلك <a href="https://egghead.io/courses/the-beginner-s-guide-to-reactjs" rel="external nofollow">The Beginner's Guide to React</a> جيدًا نوعًا ما. حيث يقدم المنهاجان مبادئ سنستعرضها في منهاجنا لاحقًا. <strong>وانتبه</strong> إلى أن المنهاج الأول يستخدم مكوّنات الأصناف، بينما يستخدم الثاني طريقة الدوال الجديدة.
	</li>
</ul>
<h2>
	التمارين 1.6- 1.14
</h2>

<p>
	سلّم حلول التمارين برفع الشيفرة إلى GitHub ثم أشر إلى إتمام التمارين على <a href="https://studies.cs.helsinki.fi/stats/courses/fullstackopen" rel="external nofollow">منظومة تسليم التمارين</a>. وتذكر أن تسلم تمارين القسم بالكامل دفعة واحدة , فلو سلمت تمارين قسمٍ ما، لن تكون قادررًا على تسليم غيرها من القسم ذاته. تشكل بعض التمارين جزءًا من التطبيق ذاته، يكفي في هذه الحالة رفع النسخة النهائية من التطبيق. يمكنك إن أردت الإشارة إلى ذلك بتعليق في نهاية كل تمرين، لكنه أمر غير ملزم.
</p>

<p>
	<strong>تحذير</strong> تنشئ الأداة create-react-app مستودع git محلي يحتوي المشروع ، إلا إن كان في المجلد مستودع محلي سابق. من المرجح أنك لا تريد أن يغدو المشروع مستودعًا، لهذا نفذ الأمر التالي<code>rm -rf .git</code> في مسار المشروع.
</p>

<p>
	عليك أحيانًا تنفيذ الأمر التالي في نفس المكان:
</p>

<pre class="ipsCode">
rm -rf node_modules/ &amp;&amp; npm i
</pre>

<h3>
	1.6 unicafe: الخطوة 1
</h3>

<p>
	تجمع <a href="https://www.unicafe.fi/#/9/4" rel="external nofollow">Unicafe</a> كمعظم الشركات آراء عملائها. ستكون مهمتك إنشاء تطبيق لجمع آراء العملاء. حيث يقدم التطبيق ثلاث خيارات هي جيد وعادي وسيء. يجب أن يُظهر التطبيق العدد الكلي للآراء في كل فئة. يمكن لتطبيقك أن يكون بالشكل التالي:
</p>

<p style="text-align: center;">
	<img alt="unicafe_step1_09.png" class="ipsImage ipsImage_thumbnailed" data-fileid="53803" data-unique="oxlonihib" src="https://academy.hsoub.com/uploads/monthly_2020_11/unicafe_step1_09.png.8be90e811b9ac2f165bc20468f4acd7d.png"></p>

<p>
	ينبغي لتطبيقك العمل خلال جلسة واحدة للمتصفح، وبالتالي لا بأس إن اختفت المعلومات عند إعادة تحميل الصفحة. يمكن وضع الشيفرة في ملف index.js واحد، كما يمكن الاستفادة من الشيفرة التالية كنقطة للبدء:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_140" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> useState </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">ReactDOM</span><span class="pln"> from </span><span class="str">'react-dom'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// save clicks of each button to own state</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">good</span><span class="pun">,</span><span class="pln"> setGood</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">neutral</span><span class="pun">,</span><span class="pln"> setNeutral</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">bad</span><span class="pun">,</span><span class="pln"> setBad</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      code here
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="typ">ReactDOM</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(&lt;</span><span class="typ">App</span><span class="pln"> </span><span class="pun">/&gt;,</span><span class="pln"> 
  document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'root'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">)</span></pre>

<h3>
	1.8 unicafe: الخطوة 2
</h3>

<p>
	وسّع تطبيقك ليضم إحصائيات أخرى حول آراء العملاء كالعدد الكلي للآراء و التقييم الوسطي (1 للجيد و 0 للعادي و -1 للسيء) والنسبة المئوية للآراء الإيجابية.
</p>

<p style="text-align: center;">
	<img alt="unicafe_step1_10.png" class="ipsImage ipsImage_thumbnailed" data-fileid="53804" data-unique="azu3cvqmv" src="https://academy.hsoub.com/uploads/monthly_2020_11/unicafe_step1_10.png.de14f8ebda527463f902ed83e72cefb0.png"></p>

<h3>
	1.9 unicafe: الخطوة 3
</h3>

<p>
	أعد صياغة تطبيقك بحيث توضع الإحصائيات في مكوّنها الخاص <code>Statistics</code>. ابق حالة التطبيق داخل المكوّن الجذري <code>App</code> وتذكر ألا تعرّف المكوّنات داخل المكوّنات الأخرى:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_142" style="">
<span class="com">// a proper place to define a component</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Statistics</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">good</span><span class="pun">,</span><span class="pln"> setGood</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">neutral</span><span class="pun">,</span><span class="pln"> setNeutral</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">bad</span><span class="pun">,</span><span class="pln"> setBad</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">

  </span><span class="com">// do not define a component within another component</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Statistics</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ...</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="com">// ...</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<h3>
	1.9 unicafe: الخطوة 4
</h3>

<p>
	غيّر تطبيقك لتعرض الإحصائيات حالما نحصل على رأي المستخدم.
</p>

<p style="text-align: center;">
	<img alt="unicafe_step1_11.png" class="ipsImage ipsImage_thumbnailed" data-fileid="53805" data-unique="10c244x76" src="https://academy.hsoub.com/uploads/monthly_2020_11/unicafe_step1_11.png.a9a59711c77678872504295611c62cc5.png"></p>

<h3>
	1.10 unicafe: الخطوة 5
</h3>

<p>
	سنكمل إعادة صياغة التطبيق. إفصل المكوّنين التاليين ليقوما بالتالي:
</p>

<ul>
<li>
		المكوّن <code>Button</code> سيُعرِّف الأزرار التي تُستخدم للحصول على الرأي.
	</li>
	<li>
		المكوّن <code>Statistic</code> ليظهر إحصائية واحدة مثل متوسط التقييم.
	</li>
</ul>
<p>
	لنوضح الأمر أكثر: يظهر المكوّن <code>Statistic</code> دائمًا إحصائية واحدة، بمعنى أن التطبيق يستخدم مكوّنات متعددة ليصيّر كل الإحصائيات كما يظهر في الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_144" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Statistics</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">/// ...</span><span class="pln">
  </span><span class="kwd">return</span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Statistic</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"good"</span><span class="pln"> value </span><span class="pun">={...}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Statistic</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"neutral"</span><span class="pln"> value </span><span class="pun">={...}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Statistic</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"bad"</span><span class="pln"> value </span><span class="pun">={...}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="com">// ...</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يجب أن تُبق حالة التطبيق ضمن المكوّن <code>App</code>.
</p>

<h3>
	1.11 unicafe: الخطوة 6 *
</h3>

<p>
	اعرض الإحصائيات في <a href="https://wiki.hsoub.com/HTML/table" rel="external">جدول</a> HTML ليبدو تطبيقك مماثلًا بشكل ما للصفحة التالية:
</p>

<p style="text-align: center;">
	<img alt="unicafe_step1_12.png" class="ipsImage ipsImage_thumbnailed" data-fileid="53806" data-unique="1gqdsznox" src="https://academy.hsoub.com/uploads/monthly_2020_11/unicafe_step1_12.png.2ccbcccd3c86fd8603a337bad5d975b9.png"></p>

<p>
	تذكر أن تبقي الطرفية مفتوحةً دائمًا، وإن رأيت هذا الخطأ:
</p>

<p style="text-align: center;">
	<img alt="unicafe_step1_13.png" class="ipsImage ipsImage_thumbnailed" data-fileid="53807" data-unique="m81ajn3fg" src="https://academy.hsoub.com/uploads/monthly_2020_11/unicafe_step1_13.png.eb5fd675ad107f7f23ef95d8b95917ee.png"></p>

<p>
	حاول قدر استطاعتك التخلص من التحذيرات التي ستظهر لك. حاول البحث في Google عن رسائل الخطأ التي تصادفك إن لم تتمكن من إيجاد الحل. فمثلًا، المصدر النموذجي للخطأ:
</p>

<pre class="ipsCode" id="ips_uid_5307_148">
Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist</pre>

<p>
	هو موسّع للمتصفح Chrome. ادخل إلى <code>/chrome://extensions</code> ثم الغ تفعيل الموسّعات واحدًا تلو الآخر حتى تقف على الموسّع الذي سبب الخطأ، ثم أعد تحميل الصفحة. من المفترض أن يصحح ذلك الخطأ.
</p>

<p>
	<strong>احرص من الآن فصاعدًا أن لا ترى أية تحذيرات على متصفحك</strong>
</p>

<h3>
	1.12 طرائف: خطوة 1 *
</h3>

<p>
	يمتلئ عالم هندسة البرمجيات <a href="http://www.comp.nus.edu.sg/~damithch/pages/SE-quotes.htm" rel="external nofollow">بالطرائف</a> التي تختصر الحقائق الخالدة في هذا المجال في سطر واحد قصير. وسّع التطبيق التالي بإضافة زر يعرض بالنقر عليه طرفة مختارة عشوائيًا من مجال هندسة البرمجيات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_150" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> useState </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">ReactDOM</span><span class="pln"> from </span><span class="str">'react-dom'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">selected</span><span class="pun">,</span><span class="pln"> setSelected</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">anecdotes</span><span class="pun">[</span><span class="pln">selected</span><span class="pun">]}</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> anecdotes </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
  </span><span class="str">'If it hurts, do it more often'</span><span class="pun">,</span><span class="pln">
  </span><span class="str">'Adding manpower to a late software project makes it later!'</span><span class="pun">,</span><span class="pln">
  </span><span class="str">'The first 90 percent of the code accounts for the first 90 percent of the development time...The remaining 10 percent of the code accounts for the other 90 percent of the development time.'</span><span class="pun">,</span><span class="pln">
  </span><span class="str">'Any fool can write code that a computer can understand. Good programmers write code that humans can understand.'</span><span class="pun">,</span><span class="pln">
  </span><span class="str">'Premature optimization is the root of all evil.'</span><span class="pun">,</span><span class="pln">
  </span><span class="str">'Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.'</span><span class="pln">
</span><span class="pun">]</span><span class="pln">

</span><span class="typ">ReactDOM</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="typ">App</span><span class="pln"> anecdotes</span><span class="pun">={</span><span class="pln">anecdotes</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;,</span><span class="pln">
  document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'root'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">)</span></pre>

<p>
	ابحث في Google عن طريقة توليد الأرقام العشوائية في JavaScript. ولا تنس أن تجرب توليد الأرقام العشوائية بعرضها مباشرة على طرفيّة المتصفح. سيبدو التطبيق عندما ينتهي قريبًا من الشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="53794" href="https://academy.hsoub.com/uploads/monthly_2020_11/anecdotes_step1_14.png.bee1a7116197bab889a44f354609dedd.png" rel=""><img alt="anecdotes_step1_14.png" class="ipsImage ipsImage_thumbnailed" data-fileid="53794" data-unique="0h6vdhhlv" src="https://academy.hsoub.com/uploads/monthly_2020_11/anecdotes_step1_14.png.bee1a7116197bab889a44f354609dedd.png"></a>
</p>

<p>
	<strong>تحذير</strong> تنشئ الأداة create-react-app مستودع git محلي يحتوي المشروع ، إلا إن كان في المجلد مستودع محلي سابق. من المرجح أنك لا تريد أن يغدو المشروع مستودعًا، لهذا نفذ الأمر التالي<code>rm -rf .git</code> في مسار المشروع.
</p>

<h3>
	1.13 طرائف: خطوة 2 *
</h3>

<p>
	وسّع تطبيقك بحيث يمكنك التصويت لصالح الطرفة المعروضة.
</p>

<p style="text-align: center;">
	<img alt="anecdotes_step1_15.png" class="ipsImage ipsImage_thumbnailed" data-fileid="53795" data-unique="ra20gk94c" src="https://academy.hsoub.com/uploads/monthly_2020_11/anecdotes_step1_15.png.252f355ba95a72112855319cbba40f73.png"></p>

<p>
	<strong>ملاحظة</strong>: خزن نتائج التصويت على كل طرفة في مصفوفة كائنات ضمن مكوّن الحالة. وتذكر أن الطريقة الصحيحة لتحديث حالة التطبيق المخزنة في البنى المعقدة للبيانات كالمصفوفات والكائنات هو إنشاء نسخة للحالة. يمكنك نسخ الكائن كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_152" style="">
<span class="kwd">const</span><span class="pln"> points </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="lit">0</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> copy </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">...</span><span class="pln">points </span><span class="pun">}</span><span class="pln">
</span><span class="com">// زيادة قيمة الخاصية 2 بمقدار 1   </span><span class="pln">
copy</span><span class="pun">[</span><span class="lit">2</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">     </span></pre>

<p>
	أو نسخ مصفوفة على النحو:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5307_154" style="">
<span class="kwd">const</span><span class="pln"> points </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">]</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> copy </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[...</span><span class="pln">points</span><span class="pun">]</span><span class="pln">
</span><span class="com">// زيادة القيمة في الموقع 2 من المصفوفة بمقدار 1</span><span class="pln">
copy</span><span class="pun">[</span><span class="lit">2</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">     </span></pre>

<p>
	استخدم المصفوفة فقد يكون ذلك الخيار الأبسط في هذه الحالة. سيساعدك البحث في Google على إيجاد الكثير من التلميحات عن كيفية <a href="https://stackoverflow.com/questions/20222501/how-to-create-a-zero-filled-javascript-array-of-arbitrary-length/22209781" rel="external nofollow">إنشاء مصفوفة</a> من الأصفار بالطول الذي تريد.
</p>

<h3>
	1.14 طرائف: الخطوة 3*
</h3>

<p>
	اجعل النسخة النهائية للتطبيق قادرة على عرض الطرفة التي تحقق أعلى عدد من الأصوات:
</p>

<p style="text-align: center;">
	<img alt="anecdotes_step1_16.png" class="ipsImage ipsImage_thumbnailed" data-fileid="53796" data-unique="f989iwwp3" src="https://academy.hsoub.com/uploads/monthly_2020_11/anecdotes_step1_16.png.53a220e9f801d717ef55fc44c900fb16.png"></p>

<p>
	يكفي أن تعرض إحدى الطرائف التي تحقق نفس العدد من الأصوات.
</p>

<p>
	لقد وصلنا إلى نهاية تمارين القسم 1 من المنهاج وحان الوقت لتسليم الحلول إلى GitHub. لا تنسى تحديد التمارين التي سلمتها في <a href="https://studies.cs.helsinki.fi/stats/courses/fullstackopen" rel="external nofollow">منظومة تسليم التمارين</a>.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://fullstackopen.com/en/part1/a_more_complex_state_debugging_react_apps" rel="external nofollow">JavaScript</a> من سلسلة <a href="https://fullstackopen.com/en/" rel="external nofollow">Deep Dive Into Modern Web Development</a>
</p>
]]></description><guid isPermaLink="false">1075</guid><pubDate>Fri, 20 Nov 2020 13:00:00 +0000</pubDate></item><item><title>&#x62D;&#x627;&#x644;&#x629; &#x627;&#x644;&#x645;&#x643;&#x648;&#x646;&#x627;&#x62A; Component state &#x648;&#x645;&#x639;&#x627;&#x644;&#x62C;&#x627;&#x62A; &#x627;&#x644;&#x623;&#x62D;&#x62F;&#x627;&#x62A; event handlers &#x641;&#x64A; React</title><link>https://academy.hsoub.com/programming/javascript/react/%D8%AD%D8%A7%D9%84%D8%A9-%D8%A7%D9%84%D9%85%D9%83%D9%88%D9%86%D8%A7%D8%AA-component-state-%D9%88%D9%85%D8%B9%D8%A7%D9%84%D8%AC%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D8%AD%D8%AF%D8%A7%D8%AA-event-handlers-%D9%81%D9%8A-react-r1074/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_11/3.png.ee7fa71526138c6a213e7acb69b89a71.png" /></p>

<p>
	لنعد إلى العمل مع React، ولنبدأ بمثالٍ جديد:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_7" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Hello</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="typ">Hello</span><span class="pln"> </span><span class="pun">{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">name</span><span class="pun">},</span><span class="pln"> you are </span><span class="pun">{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">age</span><span class="pun">}</span><span class="pln"> years old
      </span><span class="pun">&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> name </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Peter'</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> age </span><span class="pun">=</span><span class="pln"> </span><span class="lit">10</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Greetings</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Hello</span><span class="pln"> name</span><span class="pun">=</span><span class="str">"Maya"</span><span class="pln"> age</span><span class="pun">={</span><span class="lit">26</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">10</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Hello</span><span class="pln"> name</span><span class="pun">={</span><span class="pln">name</span><span class="pun">}</span><span class="pln"> age</span><span class="pun">={</span><span class="pln">age</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	الدوال المساعدة لمكون
</h2>

<p>
	لنوسع المكوّن <code>Hello</code> بحيث يحدد العام الذي ولد فيه الشخص الذي نحيّيه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_9" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Hello</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> bornYear </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">    
    </span><span class="kwd">const</span><span class="pln"> yearNow </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">().</span><span class="pln">getFullYear</span><span class="pun">()</span><span class="pln">    
    </span><span class="kwd">return</span><span class="pln"> yearNow </span><span class="pun">-</span><span class="pln"> props</span><span class="pun">.</span><span class="pln">age
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="typ">Hello</span><span class="pln"> </span><span class="pun">{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">name</span><span class="pun">},</span><span class="pln"> you are </span><span class="pun">{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">age</span><span class="pun">}</span><span class="pln"> years old
      </span><span class="pun">&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="typ">So</span><span class="pln"> you were probably born in </span><span class="pun">{</span><span class="pln">bornYear</span><span class="pun">()}&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وُضعت الشيفرة التي تحدد عام الولادة ضمن دالة منفصلة تُستدعى حين يُصيَّر المكوّن. لا داعي لتمرير عمر الشخص إلى الدالة كمُعامل لأنها قادرة على الوصول إلى الخصائص (props) مباشرة. لو تفحّصنا الشيفرة المكتوبة عن قرب، لوجدنا أن الدالة المساعدة (helper function) قد عُرّفت داخل دالة أخرى تحدد عمل المكوّن. لا يُستخدَم هذا الأسلوب في Java كونه أمرًا معقدًا ومزعجًا، لكنه مستخدم جدًا في JavaScript.
</p>

<h2>
	التفكيك Destructuring
</h2>

<p>
	قبل أن نمضي قدمًا، سنلقي نظرة على ميزة بسيطة لكنها مفيدة أضيفت في النسخة ES6. تسمح هذه الميزة <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%A5%D8%B3%D9%86%D8%A7%D8%AF-%D8%A8%D8%A7%D9%84%D8%AA%D9%81%D9%83%D9%8A%D9%83-destructuring-assignment-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r824/" rel="">بتفكيك</a> القيم عن الكائنات والمصفوفات عند إسنادها. لقد ربطنا البيانات التي مررناها إلى المكوّن مستخدمين العبارتين <code>props.name</code> و<code>props.age</code>. كما كررنا أيضا العبارة <code>props.age</code> مرتين في الشيفرة. وطالما أن <code>props</code> هو كائن له الشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_11" style="">
<span class="pln">props </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Arto Hellas'</span><span class="pun">,</span><span class="pln">
  age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">35</span><span class="pun">,</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سنجعل المكوّن أكثر حيوية بإسناد قيمتي خاصيّتيه مباشرة إلى المتغّيرين <code>name</code> و<code>age</code>، ومن ثم نستخدمهما في الشيفرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_13" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Hello</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> name </span><span class="pun">=</span><span class="pln"> props</span><span class="pun">.</span><span class="pln">name  
  </span><span class="kwd">const</span><span class="pln"> age </span><span class="pun">=</span><span class="pln"> props</span><span class="pun">.</span><span class="pln">age
  </span><span class="kwd">const</span><span class="pln"> bornYear </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">().</span><span class="pln">getFullYear</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> age

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="typ">Hello</span><span class="pln"> </span><span class="pun">{</span><span class="pln">name</span><span class="pun">},</span><span class="pln"> you are </span><span class="pun">{</span><span class="pln">age</span><span class="pun">}</span><span class="pln"> years old</span><span class="pun">&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="typ">So</span><span class="pln"> you were probably born in </span><span class="pun">{</span><span class="pln">bornYear</span><span class="pun">()}&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لاحظ كيف استخدمنا العبارة المختصرة للدوال السهمية عندما عرفنا الدالة <code>bornYear</code>. لقد أشرنا إلى هذه النقطة سابقًا، فلا حاجة لوضع جسم الدالة السهمية بين قوسين معقوصين إذا احتوت على عبارة واحدة فقط، حيث تعيد الدالة نتيجة تنفيذ تلك العبارة. وبالتالي فالطريقتان المستخدمتان في تعريف الدالتين التاليتين متطابقتان:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_15" style="">
<span class="kwd">const</span><span class="pln"> bornYear </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">().</span><span class="pln">getFullYear</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> age

</span><span class="kwd">const</span><span class="pln"> bornYear </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">().</span><span class="pln">getFullYear</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> age
</span><span class="pun">}</span></pre>

<p>
	إذًا تُسهّل عملية التفكيك إسناد القيم للمتغيّرات، حيث نستخلص قيم خصائص الكائنات ونضعها في متغيّرات منفصلة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_17" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Hello</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> name</span><span class="pun">,</span><span class="pln"> age </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> props  </span><span class="kwd">const</span><span class="pln"> bornYear </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">().</span><span class="pln">getFullYear</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> age

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="typ">Hello</span><span class="pln"> </span><span class="pun">{</span><span class="pln">name</span><span class="pun">},</span><span class="pln"> you are </span><span class="pun">{</span><span class="pln">age</span><span class="pun">}</span><span class="pln"> years old</span><span class="pun">&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="typ">So</span><span class="pln"> you were probably born in </span><span class="pun">{</span><span class="pln">bornYear</span><span class="pun">()}&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	فلو افترضنا أنّ الكائن الذي نفككه يمتلك القيم التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_19" style="">
<span class="pln">props </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Arto Hellas'</span><span class="pun">,</span><span class="pln">
  age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">35</span><span class="pun">,</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ستُسنِد العبارة <code>const { name, age } = props</code> القيمة "Arto Hellas" إلى المتغيّر <code>name</code> والقيمة "35" إلى المتغيّر <code>age</code>. سنتعمق قليلًا في فكرة التفكيك:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_21" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Hello</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> name</span><span class="pun">,</span><span class="pln"> age </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  
  </span><span class="kwd">const</span><span class="pln"> bornYear </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">().</span><span class="pln">getFullYear</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> age

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="typ">Hello</span><span class="pln"> </span><span class="pun">{</span><span class="pln">name</span><span class="pun">},</span><span class="pln"> you are </span><span class="pun">{</span><span class="pln">age</span><span class="pun">}</span><span class="pln"> years old
      </span><span class="pun">&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="typ">So</span><span class="pln"> you were probably born in </span><span class="pun">{</span><span class="pln">bornYear</span><span class="pun">()}&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لقد فككت الشيفرة السابقة الخاصيتين اللتين يمتلكهما المكوّن وأسندتهما مباشرة إلى المتغيّرين <code>name</code> و<code>age</code>. أي باختصار لم نسند الكائن الذي يدعى <code>props</code> إلى متغيّر يدعى <code>props</code> ثم أسندت خاصيتيه إلى المتغيّرين <code>name</code> و<code>age</code> كما يحدث في الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_23" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Hello</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> name</span><span class="pun">,</span><span class="pln"> age </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> props</span></pre>

<p>
	بل أسندت قيمتي الخاصيتين مباشرة إلى المتغيّرات بتفكيك الكائن <code>props</code> أثناء تمريره كمُعامل لدالة المكوًن:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_25" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Hello</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> name</span><span class="pun">,</span><span class="pln"> age </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span></pre>

<h2>
	إعادة تصيير الصفحة Page re-rendering
</h2>

<p>
	لم تطرأ أية تغييرات على مظهر التطبيقات التي كتبناها حتى الآن. ماذا لو أردنا أن ننشئ عدادًا تزداد قيمته مع الوقت أو عند النقر على زر؟ لنبدأ بالشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_27" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln">counter</span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> props
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;{</span><span class="pln">counter</span><span class="pun">}&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let counter </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">

</span><span class="typ">ReactDOM</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="typ">App</span><span class="pln"> counter</span><span class="pun">={</span><span class="pln">counter</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;,</span><span class="pln"> 
  document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'root'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">)</span></pre>

<p>
	تُمرَّر قيمة العدّاد إلى المكوّن <code>App</code> عبر الخاصيّة <code>counter</code>، ثم سيعمل على تصييرها على الشاشة. لكن ما الذي سيحدث لو تغيرت قيمة <code>counter</code>؟ حتى لو زدنا قيمتها تدريجيًا كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_35" style="">
<span class="pln">counter </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span></pre>

<p>
	فلن يصيّر المكوّن القيمة الجديدة على الشاشة. لحل المشكلة، علينا استدعاء التابع <code>ReactDOM.render</code> حتى يُعاد تصيير الصفحة مجددًا بالطريقة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_37" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> counter </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> props
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;{</span><span class="pln">counter</span><span class="pun">}&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

let counter </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> refresh </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="typ">ReactDOM</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(&lt;</span><span class="typ">App</span><span class="pln"> counter</span><span class="pun">={</span><span class="pln">counter</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;,</span><span class="pln"> 
  document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'root'</span><span class="pun">))</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

refresh</span><span class="pun">()</span><span class="pln">
counter </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
refresh</span><span class="pun">()</span><span class="pln">
counter </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
refresh</span><span class="pun">()</span></pre>

<p>
	غُلّف أمر إعادة تصيير الصفحة داخل الدالة <code>refresh</code> لتَسهُل كتابة الشيفرة. لاحظ كيف أعيد تصيير المركب ثلاث مرات، الأولى عندما كانت قيمة العدّاد 1 ثم 2 وأخيرًا 3. وطبعًا لن تلاحظ ظهور القيمتين 1 و2 نظرًا لفترة ظهورهما القصيرة جدًا. يمكننا أن نجعل الأداء أفضل قليلًا بتصيير الصفحة وزيادة العدّاد كل ثانية مستخدمين الدالة <a href="https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval" rel="external nofollow">setInterval</a> التي تنفذ ما بداخلها خلال فترة زمنية محددة بالميلي ثانية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_39" style="">
<span class="pln">setInterval</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  refresh</span><span class="pun">()</span><span class="pln">
  counter </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
</span><span class="pun">},</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">)</span></pre>

<p>
	وأخيرًا لا تكرر استدعاء التابع <code>ReactDOM.render</code>، ولا ننصحك بذلك، لأنك ستتعلم لاحقًا طريقةً أفضل.
</p>

<h2>
	مكوّن متغير الحالات Stateful component
</h2>

<p>
	تبدو جميع المكوّنات التي تعاملنا معها حتى الآن بسيطة من مبدأ أنها لم تحتوي على حالات قد تتغير خلال فترة عمل المكوّن، لذلك سنضيف الآن حالة إلى المكوّن <code>App</code> بمساعدة أحد خطافات React وهو <a href="https://wiki.hsoub.com/React/hooks_state" rel="external">state hook</a>. فلنقم إذًا بتعديل التطبيق على النحو:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_42" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> useState </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react'</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">ReactDOM</span><span class="pln"> from </span><span class="str">'react-dom'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> counter</span><span class="pun">,</span><span class="pln"> setCounter </span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
  setTimeout</span><span class="pun">(</span><span class="pln">    </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setCounter</span><span class="pun">(</span><span class="pln">counter </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">),</span><span class="pln">    </span><span class="lit">1000</span><span class="pln">  </span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;{</span><span class="pln">counter</span><span class="pun">}&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="typ">ReactDOM</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="typ">App</span><span class="pln"> </span><span class="pun">/&gt;,</span><span class="pln"> 
  document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'root'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">)</span></pre>

<p>
	يُدرِج التطبيق في السطر الأول الدالة <code>useState</code> باستخدام الكلمة <code>import</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_44" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> useState </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'react'</span></pre>

<p>
	تبدأ التعليمات داخل دالة المكوّن باستدعاء دالة أخرى كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_46" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> counter</span><span class="pun">,</span><span class="pln"> setCounter </span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span></pre>

<p>
	تضيف الدالة المستدعاة <code>useState</code> "حالة" وتصيّرها بعد إعطائها قيمة ابتدائية تساوي 0. بعدها تعيد الدالة مصفوفة تضم عنصرين تسندهما إلى المتغيّرين <code>counter</code> و<code>setCounter</code> مستخدمةً الإسناد بالتفكيك. سيحمل المتغيّر <code>counter</code> القيمة الابتدائية للحالة وهي 0، بينما سيحمل <code>setCounter</code> القيمة التي تعيدها الدالة المغيّرة للحالة. يستدعي التطبيق بعد ذلك الدالة <a href="https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout" rel="external nofollow">setTimeout</a> ويمرر لها مُعاملان أحدهما دالة لزيادة قيمة العدّاد، والآخر لتحديد وقت الانتهاء (timeout) بثانية واحدة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_48" style="">
<span class="pln">setTimeout</span><span class="pun">(</span><span class="pln">
  </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setCounter</span><span class="pun">(</span><span class="pln">counter </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">),</span><span class="pln">
  </span><span class="lit">1000</span><span class="pln">
</span><span class="pun">)</span></pre>

<p>
	تُستدعى الدالة <code>setCounter</code> التي مُررت كمُعامل للدالة <code>setTimeout</code> بعد ثانية من استدعاء الأخيرة.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_50" style="">
<span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setCounter</span><span class="pun">(</span><span class="pln">counter </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span></pre>

<p>
	تعيد React تصييرالمكوّن بعد استدعاء الدالة <code>setCounter</code> والتي تعتبر هنا الدالة المغيّرة للحالة (كونها غيرت قيمة العدّاد)، ويعني هذا إعادة تنفيذ الشيفرة في دالة المكوّن:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_52" style="">
<span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> counter</span><span class="pun">,</span><span class="pln"> setCounter </span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">

  setTimeout</span><span class="pun">(</span><span class="pln">
    </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setCounter</span><span class="pun">(</span><span class="pln">counter </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">),</span><span class="pln">
    </span><span class="lit">1000</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;{</span><span class="pln">counter</span><span class="pun">}&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	عندما تُنفَّذ دالة المكوّن ثانيةً، سيستدعي الدالة <code>useState</code> ثم يعيد القيمة الجديدة للحالة:1. وكذلك الأمر سيُستدعى <code>setTimeout</code> مجددًا والذي سيستدعي بدوره <code>setCounter</code> بعد انقضاء ثانية وسيزيد العدّاد هنا بمقدار 1 ليصبح 2 بعد أن أصبحت قيمة <code>counter</code> تساوي 1.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_54" style="">
<span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setCounter</span><span class="pun">(</span><span class="lit">2</span><span class="pun">)</span></pre>

<p>
	خلال هذه العملية ستظهر على الشاشة القيمة الأقدم للعدّاد. وهكذا سيعاد تصيير الكائن في كل مرة تغيّر فيها الدالة <code>setCounter</code> حالة المكوّن، وستزداد قيمة العدّاد مع تكرار العملية طالما أن التطبيق يعمل.
</p>

<p>
	إن لم تحدث عملية إعادة التصيير في الوقت المحدد أو ظننت أنها تحصل في توقيت خاطئ، يمكنك تنقيح (Debug) التطبيق بإظهار قيم المتغيّرات على الطرفية بالطريقة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_56" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> counter</span><span class="pun">,</span><span class="pln"> setCounter </span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">

  setTimeout</span><span class="pun">(</span><span class="pln">
    </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setCounter</span><span class="pun">(</span><span class="pln">counter </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">),</span><span class="pln">
    </span><span class="lit">1000</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">

  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'rendering...'</span><span class="pun">,</span><span class="pln"> counter</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;{</span><span class="pln">counter</span><span class="pun">}&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	فمن السهل عندها تتبع ومراقبة استدعاءات دالة التصيير:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="53792" href="https://academy.hsoub.com/uploads/monthly_2020_11/follow_render_function_01.png.6190ec0fa3d9006b55dc717b539724f8.png" rel=""><img alt="follow_render_function_01.png" class="ipsImage ipsImage_thumbnailed" data-fileid="53792" data-unique="ob879zgzj" src="https://academy.hsoub.com/uploads/monthly_2020_11/follow_render_function_01.png.6190ec0fa3d9006b55dc717b539724f8.png"></a>
</p>

<h2>
	معالجة الأحداث Event handling
</h2>

<p>
	أشرنا في <a href="https://academy.hsoub.com/programming/javascript/react/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r1071/" rel="">القسم 0</a> في مواضع عدة إلى معالجات الأحداث، وهي دوال تُستدعَى عندما يقع حدث ما في زمن التشغيل. فعندما يتعامل المستخدم مع العناصر المختلفة لصفحة الويب، سيحرّض ذلك مجموعة مختلفة من الأحداث. لنعدّل تطبيقنا قليلًا بحيث تزداد قيمة العدّاد عندما ينقر المستخدم على زر، سنستخدم هنا العنصر <a href="https://wiki.hsoub.com/HTML/button" rel="external">button</a>. تدعم هذه العناصر ما يسمى بأحداث الفأرة (<a href="https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent" rel="external nofollow">mouse events</a>)، وأكثر هذه الأحداث شيوعًا هو حدث النقر على الزر(<a href="https://developer.mozilla.org/en-US/docs/Web/Events/click" rel="external nofollow">click</a>). <a href="https://wiki.hsoub.com/React/handling_events" rel="external">يُسجَّل</a> معالج حدث النقر في React كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_58" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> counter</span><span class="pun">,</span><span class="pln"> setCounter </span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> handleClick </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'clicked'</span><span class="pun">)</span><span class="pln">  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;{</span><span class="pln">counter</span><span class="pun">}&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">handleClick</span><span class="pun">}&gt;</span><span class="pln">
        plus
      </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	نحدد من خلال الصفة <code>onClick</code> للعنصر <code>button</code> أن الدالة <code>handleClick</code> ستتولى معالجة حدث النقر على زر الفأرة. وهكذا ستُستدعَى الدالة <code>handleClick</code> في كل مرة ينقر فيها المستخدم على الزر <code>plus</code>، وستظهر الرسالة "clicked" على طرفية المتصفح. كما يُعرّف معالج الحدث أيضًا باسناده مباشرة إلى الصفة <code>onClick</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_60" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> counter</span><span class="pun">,</span><span class="pln"> setCounter </span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;{</span><span class="pln">counter</span><span class="pun">}&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'clicked'</span><span class="pun">)}&gt;</span><span class="pln">
        plus
      </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وبتغيير الشيفرة التي ينفذها معالج الحدث لتصبح على النحو:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_62" style="">
<span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setCounter</span><span class="pun">(</span><span class="pln">counter </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)}&gt;</span><span class="pln">
  plus
</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span></pre>

<p>
	سنحصل على السلوك المطلوب وهو زيادة العدّاد بمقدار 1 وإعادة تصييرالمكوّن. سنضيف الآن زرًا آخر لتصفير العدّاد:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_64" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> counter</span><span class="pun">,</span><span class="pln"> setCounter </span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;{</span><span class="pln">counter</span><span class="pun">}&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setCounter</span><span class="pun">(</span><span class="pln">counter </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)}&gt;</span><span class="pln">
        plus
      </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setCounter</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)}&gt;</span><span class="pln">
        zero      
      </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وهكذا سيكون تطبيقنا جاهزًا الآن.
</p>

<h2>
	معالج الحدث هو دالة
</h2>

<p>
	لقد عرفنا سابقًا معالج الحدث كقيمة للصفة <code>onClick</code> لعنصر الزر (button):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_66" style="">
<span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setCounter</span><span class="pun">(</span><span class="pln">counter </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)}&gt;</span><span class="pln"> 
  plus
</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span></pre>

<p>
	لكن ماذا لو عرّفنا معالج الحدث بشكل أبسط كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_68" style="">
<span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">setCounter</span><span class="pun">(</span><span class="pln">counter </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)}&gt;</span><span class="pln"> 
  plus
</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span></pre>

<p>
	سيدمر هذا العمل التطبيق:
</p>

<p style="text-align: center;">
	<img alt="re-render_error_02.png" class="ipsImage ipsImage_thumbnailed" data-fileid="53793" data-unique="ncdmqu10i" src="https://academy.hsoub.com/uploads/monthly_2020_11/re-render_error_02.png.5ad90c57f8b236b955e6c8cf16942fe1.png"></p>

<p>
	ماذا حدث؟ يفترض أن يكون معالج الحدث دالة أو مرجعًا إلى دالة، فعندما نعرّفه على النحو:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_71" style="">
<span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">setCounter</span><span class="pun">(</span><span class="pln">counter </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)}&gt;</span></pre>

<p>
	يمثل معالج الحدث بهذه الطريقة استدعاءً لدالة، وقد يكتب بالشكل السابق، لكن ليس في حالتنا الخاصة هذه. حيث تكون قيمة <code>counter</code> في البداية 0، ثم تُصيّر React التابع للمرة الأولى مستدعيةً الدالة <code>(setCounter(0+1</code> التي ستُغير الحالة من 0 إلى 1، وفي نفس الوقت تعيد React تصييرالمكوّن مستدعيةً من جديد<code>setCounter</code>، وستتغير الحالة مجددًا يعقبها إعادة تصيير وهكذا. لنعد الآن إلى تعريف معالج الحدث بالشكل الصحيح:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_73" style="">
<span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setCounter</span><span class="pun">(</span><span class="pln">counter </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)}&gt;</span><span class="pln"> 
  plus
</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span></pre>

<p>
	تمتلك الآن الصفة <code>onClick</code> التي تحدد ما يجري عند النقر على الزر، القيمة الناتجة عن تنفيذ <code>(setCounter(counter+1)&lt;=()</code> وبذلك تزداد قيمة العدّاد فقط عندما ينقر المستخدم على الزر. لا يعتبر تعريف معالجات الأحداث باستخدام قوالب JSX فكرة جيدة. لا بأس بذلك في حالتنا هذه لأن معالج الحدث بسيط جدًا. لنقم بفصل معالج الحدث إلى عدة دوال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_75" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> counter</span><span class="pun">,</span><span class="pln"> setCounter </span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> increaseByOne </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setCounter</span><span class="pun">(</span><span class="pln">counter </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln">    
  </span><span class="kwd">const</span><span class="pln"> setToZero </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setCounter</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;{</span><span class="pln">counter</span><span class="pun">}&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">increaseByOne</span><span class="pun">}&gt;</span><span class="pln">
        plus
      </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">setToZero</span><span class="pun">}&gt;</span><span class="pln">
        zero
      </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لقد عُرّف معالج الحدث في الشيفرة السابقة بشكلٍ صحيح، حيث أُسند للصفة <code>onClick</code> متغيّر يتضمن مرجعًا لدالة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_77" style="">
<span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">increaseByOne</span><span class="pun">}&gt;</span><span class="pln"> 
  plus
</span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span></pre>

<h2>
	تمرير الحالة إلى المكوّنات الأبناء (child components)
</h2>

<p>
	يفضل عند كتابة مكونات React أن تكون صغيرة وقابلة للاستخدام المتكرر ضمن التطبيق وحتى عبر المشاريع المختلفة. لنُعِد صياغة تطبيقنا إذًا حتى يضم ثلاث مكونات أصغر، الأول لإظهار العدّاد والآخرين للزرين. لنبدأ بالمكون <code>Display</code> الذي سيكون مسؤولًا عن إظهار قيمة العدّاد على الشاشة. من الأفضل الإبقاء على حالة التطبيق ضمن مكونات المستوى الأعلى (<a href="https://reactjs.org/docs/lifting-state-up.html" rel="external nofollow">lift the state up</a>)، حيث ينص التوثيق على ما يلي:
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p>
		<strong>عندما تحتاج عدة مكونات لإظهار نفس البيانات التي تتغير، ننصح بالاحتفاظ بالحالة المشتركة ضمن المكوّن الأب الأقرب لهذه المكوّنات</strong>
	</p>
</blockquote>

<p>
	لذا سنضع حالة التطبيق في المكوّن <code>App</code>، ونمرره نزولًا إلى المكوّن <code>Display</code> عبر الخصائص:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_79" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Display</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">counter</span><span class="pun">}&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سنستخدم المكوّن مباشرة، إذ علينا فقط أن نمرر إليه حالة المتغيّر <code>counter</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_81" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> counter</span><span class="pun">,</span><span class="pln"> setCounter </span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> increaseByOne </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setCounter</span><span class="pun">(</span><span class="pln">counter </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> setToZero </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setCounter</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Display</span><span class="pln"> counter</span><span class="pun">={</span><span class="pln">counter</span><span class="pun">}/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">increaseByOne</span><span class="pun">}&gt;</span><span class="pln">
        plus
      </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">setToZero</span><span class="pun">}&gt;</span><span class="pln"> 
        zero
      </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيجري كل شيء بشكل طبيعي، فحين ننقر الزر سيعاد تصيير المكوّن <code>App</code> وكذلك المكوّن الابن<code>Display</code>. سننشئ تاليًا المكوّن <code>Button</code> ليمثل أزرار التطبيق. علينا أن نمرر معالجات الأحداث وعنوان الزر عبر خصائص المكوّن:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_83" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Button</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">props</span><span class="pun">.</span><span class="pln">handleClick</span><span class="pun">}&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">text</span><span class="pun">}</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيبدو المكوّن <code>App</code> الآن بهذا الشكل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_85" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> counter</span><span class="pun">,</span><span class="pln"> setCounter </span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useState</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> increaseByOne </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setCounter</span><span class="pun">(</span><span class="pln">counter </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> decreaseByOne </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setCounter</span><span class="pun">(</span><span class="pln">counter </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> setToZero </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setCounter</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Display</span><span class="pln"> counter</span><span class="pun">={</span><span class="pln">counter</span><span class="pun">}/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Button</span><span class="pln">
        handleClick</span><span class="pun">={</span><span class="pln">increaseByOne</span><span class="pun">}</span><span class="pln">
        text</span><span class="pun">=</span><span class="str">'plus'</span><span class="pln">
      </span><span class="pun">/&gt;</span><span class="pln">      
      </span><span class="pun">&lt;</span><span class="typ">Button</span><span class="pln">
        handleClick</span><span class="pun">={</span><span class="pln">setToZero</span><span class="pun">}</span><span class="pln">
        text</span><span class="pun">=</span><span class="str">'zero'</span><span class="pln">
      </span><span class="pun">/&gt;</span><span class="pln">           
      </span><span class="pun">&lt;</span><span class="typ">Button</span><span class="pln">
        handleClick</span><span class="pun">={</span><span class="pln">decreaseByOne</span><span class="pun">}</span><span class="pln">
        text</span><span class="pun">=</span><span class="str">'minus'</span><span class="pln">
      </span><span class="pun">/&gt;</span><span class="pln">               
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	طالما أننا حصلنا على المكوّن <code>Button</code> الذي يمكن استخدامه بسهولة أينما كان، سنزيد من إمكانية التطبيق بإضافة زر جديد ليُنقص قيمة العدّاد. يمرر معالج الحدث إلى المكوّن <code>Button</code> عبر الخاصية <code>handleClick</code>. ليس مهمًا الاسم الذي اطلقناه على الخاصية، لكننا لم نختره عشوائيًا أيضًا، فقد اقترح أسلوب التسمية هذا في <a href="https://wiki.hsoub.com/React/tutorial" rel="external">الدورة التعليمية</a> الرسمية لمكتبة React.
</p>

<h2>
	تغّير الحالة يستوجب إعادة التصيير
</h2>

<p>
	لنستعرض المبدأ الرئيسي لعمل التطبيق مرّة أخرى. عندما يبدأ العمل ستُنفَّذ شيفرة المكوّن <code>App</code>. تستخدم تلك الشيفرة الخطاف <a href="https://wiki.hsoub.com/React/hooks_reference#useState" rel="external">useState</a> لبناء حالة التطبيق وتحدد القيمة البدائية للمتغيّر <code>counter</code>. يضم هذا المكوّن مكوّنًا آخر هو <code>Display</code> الذي يعرض القيمة البدائية 0 للعداد، كما يضم ثلاثة مكونات <code>Button</code>، ولكل ٍّ منها معالج حدث يغيّر حالة العدّاد. فعندما يُنقر أي زر سيُنفَّذ معالج الحدث المقابل والذي يستخدم الدالة <code>setCounter</code> لتغيير حالة المكوّن <code>App</code>. ودائمًا <strong>استدعاء الدالة التي تغير حالة المكوّن يستوجب إعادة التصيير</strong>. فلو نقر المستخدم زر الزيادة (زر عنوانه plus)، سيغيّر معالج الحدث الخاص به قيمة العدّاد إلى 1، وسيعاد تصيير المكوّن <code>App</code>. سيستقبل المكوّن <code>Display</code> أيضًا قيمة العدّاد الجديدة كخاصية، كما سيُزوَّد المكوّن <code>Button</code> بمعالج حدث سيُستخدم لتغيير حالة العدّاد.
</p>

<h2>
	إعادة تصميم المكوّنات Refactoring the components
</h2>

<p>
	يظهر المكوِّن الذي يعرض قيمة العدّاد على الصفحة بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_87" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Display</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">counter</span><span class="pun">}&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يستخدم المكوّن عمليًا الحقل <code>counter</code> فقط من الخصائص، لهذا يمكن تبسيطه باستخدام التفكيك كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_89" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Display</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> counter </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;{</span><span class="pln">counter</span><span class="pun">}&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يضم التابع الذي يعرّف المكوّن العبارة التي تعيد نتيجة التنفيذ فقط، لذا يمكننا كتابته بالطريقة المختصرة التي تقدمها الدوال السهمية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_91" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Display</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> counter </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;{</span><span class="pln">counter</span><span class="pun">}&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span></pre>

<p>
	لنبسط أيضًا كتابة المكوّن <code>Button</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_93" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Button</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">props</span><span class="pun">.</span><span class="pln">handleClick</span><span class="pun">}&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">text</span><span class="pun">}</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وهكذا نرى فائدة <strong>التفكيك</strong> في استخدام الحقل المطلوب فقط من الخصائص، وسهولة كتابة دوال <strong>بشكل مختصر</strong> بالاستفادة من <strong>الدوال السهمية</strong>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_361_95" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Button</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> handleClick</span><span class="pun">,</span><span class="pln"> text </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">button onClick</span><span class="pun">={</span><span class="pln">handleClick</span><span class="pun">}&gt;</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">text</span><span class="pun">}</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">button</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">)</span></pre>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://fullstackopen.com/en/part1/component_sate_event_handlers" rel="external nofollow">JavaScript</a> من سلسلة <a href="https://fullstackopen.com/en/" rel="external nofollow">Deep Dive Into Modern Web Development</a>
</p>
]]></description><guid isPermaLink="false">1074</guid><pubDate>Wed, 18 Nov 2020 13:00:00 +0000</pubDate></item><item><title>&#x623;&#x633;&#x627;&#x633;&#x64A;&#x627;&#x62A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A; &#x627;&#x644;&#x644;&#x627;&#x632;&#x645;&#x629; &#x644;&#x644;&#x639;&#x645;&#x644; &#x645;&#x639; React</title><link>https://academy.hsoub.com/programming/javascript/react/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-%D8%A7%D9%84%D9%84%D8%A7%D8%B2%D9%85%D8%A9-%D9%84%D9%84%D8%B9%D9%85%D9%84-%D9%85%D8%B9-react-r1073/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_11/2.png.7be4cb5c8b73d2e8a98bf2980c8aabb6.png" /></p>

<p>
	نهدف خلال تقدمنا في المنهاج، إلى تعلم ما يكفي عن JavaScript، فهذا أمر بالغ الأهمية، إضافة إلى تطوير الويب. لقد تطورت JavaScript بسرعة خلال السنوات القليلة الماضية، لذلك سنعتمد هنا الميزات التي توفرها النسخ الجديدة. يطلق على معيار JavaScript رسميًا اسم <a href="https://en.wikipedia.org/wiki/ECMAScript" rel="external nofollow">ECMAScript</a>. وتعتبر النسخة <a href="http://www.ecma-international.org/ecma-262/11.0/index.html" rel="external nofollow">ECMAScript® 2020</a> هي الأحدث بعد إصدارها في يونيو (حزيران) لعام 2020، كما تُعرف بالرمز ES11. لا تدعم المتصفحات الميزات الأحدث للغة JavaScript حتى الآن. لذلك نقلت الشيفرة (transpiled) التي تنفذها المتصفحات من النسخ الأحدث إلى النسخ الأقدم لتكون أكثر توافقًا. يعتبر استخدام <a href="https://babeljs.io/" rel="external nofollow">Babel</a> حاليًا أكثر الطرق شعبية لإجراء عملية النقل. وتُهيّأ عملية النقل آليًا في تطبيقات React التي تبنى باستخدام create-react-app. سنلقي نظرة أقرب إلى تهيئة عمليات النقل في القسم 7 لاحقًا.
</p>

<p>
	تُعرَّف Node.js بأنها بيئة لتنفيذ شيفرة JavaScript مبنية على محرك JavaScript الذي طورته Google والمعروف باسم <a href="https://developers.google.com/v8/" rel="external nofollow">chrome V8</a>، وتعمل هذه البيئة في أي مكان من الخوادم إلى الهواتف النقّالة. سنتدرب على كتابة شيفرة JavaScript باستخدام Node، لذلك ينبغي أن تكون نسخة Node.js المثبتة على جهازك 10.18.0 على الأقل. وطالما أنّ أحدث نسخ Node ستتوافق تلقائيًا مع أحدث نسخ JavaScript، لذلك لا حاجة لنقل الشيفرة.
</p>

<p>
	تُكتب الشيفرة في ملفات تحمل اللاحقة js. وتنفذ من خلال الأمر <code>node name_of_file.js</code>، كما يمكن أن نكتبها ضمن طرفية Node.js التي نفتحها بكتابة الأمر <code>node</code> في سطر الأوامر، وأيضًا بكتابة الأمر نفسه في طرفية التطوير الخاصة بالمتصفح. تتماشى التنقيحات الأخيرة للمتصفح Chrome جيدًا مع ميزات JavaScript الأحدث دون الحاجة إلى نقل الشيفرة. كما يمكن استخدام أدوات بديلة مثل <a href="https://jsbin.com/?js,console" rel="external nofollow">JS Bin</a>.
</p>

<p>
	تُذكِّرنا JavaScript من حيث الاسم والتعابير بلغة Java. لكن من ناحية آلية العمل فهي أبعد ماتكون عنها. فإذا نظرت إليها من منظور مبرمجي Java، سيبدو سلوكها غريبًا قليلًا وخاصة إن لم تكلّف نفسك عناء البحث في ميزاتها. لقد شاع فيما مضى محاكاة ميزات Java في تصميم نماذج JavaScript، لكننا لا نحبّذ هذا الأمر لأن اللغتين والبيئتين اللتين تعملان ضمنهما تختلفان كليًا.
</p>

<h2>
	المتغيرات Variables
</h2>

<p>
	تُعرَّف المتغيرات في JavaScript بطرقٍ عدة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7064_7" style="">
<span class="kwd">const</span><span class="pln"> x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
let y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5</span><span class="pln">

console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">)</span><span class="pln">   </span><span class="com">// 1, 5</span><span class="pln">
y </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">10</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">)</span><span class="pln">   </span><span class="com">// 1, 15</span><span class="pln">
y </span><span class="pun">=</span><span class="pln"> </span><span class="str">'sometext'</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">)</span><span class="pln">   </span><span class="com">// 1, sometext</span><span class="pln">
x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">4</span><span class="pln">               </span><span class="com">// خطا</span></pre>

<p>
	لا تُعرّف الكلمة <a href="https://wiki.hsoub.com/JavaScript/const" rel="external">const</a> متغيرًا، بل تدل على قيمة ثابتة (constant) لايمكن بعد ذلك تغييرها. بالمقابل تُعرّف الكلمة <a href="https://wiki.hsoub.com/JavaScript/let" rel="external">let</a> متغيّرًا عاديًا. يمكن أن نرى بوضوح من خلال المثال السابق أن المتغيّرات قد تأخذ بيانات من أنواع مختلفة أثناء التنفيذ، ففي البداية يخزن المتغير <code>y</code> قيمة صحيحة، ثم سلسة نصية في النهاية. كما تُستخدم الكلمة <a href="https://wiki.hsoub.com/JavaScript/var" rel="external">var</a> في تعريف المتغيّرات، فهذه الكلمة ولفترة طويلة كانت الطريقة الوحيدة لتعريف المتغيّر، ثم أضيفت <code>const</code> و<code>let</code> مؤخرًا في النسخة ES6. وقد تعمل الكلمة <code>var</code> <a href="https://medium.com/craft-academy/javascript-variables-should-you-use-let-var-or-const-394f7645c88f" rel="external nofollow">بطريقة مختلفة</a> لتعريف المتغيرات مقارنة بالطريقة التي تُعرّف بها في معظم اللغات. سنلتزم في منهاجنا باستخدام <code>const</code> و<code>let</code> عند تعريف المتغيرات. يمكنك الاطلاع على المزيد حول هذا الموضوع عبر YouTube كالفيديو التالي: <a href="https://youtu.be/sjyJBL5fkp8" rel="external nofollow">var, let and const - ES6 JavaScript Features</a>، أومن خلال المقاليين التاليين في أكاديمية حسوب:
</p>

<ul>
<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-r671/" rel="">المتغيرات في JavaScript</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A5%D9%81%D8%A7%D8%AF%D8%A9-var-%D8%A7%D9%84%D9%82%D8%AF%D9%8A%D9%85%D8%A9-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r873/" rel="">إفادة var القديمة في JavaScript</a>
	</li>
</ul>
<h2>
	المصفوفات Arrays
</h2>

<p>
	تُعرِّف الشيفرة التالية <a href="https://wiki.hsoub.com/JavaScript/Array" rel="external">مصفوفة</a> وتقدم مثالين عن كيفية استخدامها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7064_9" style="">
<span class="kwd">const</span><span class="pln"> t </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">]</span><span class="pln">

t</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="lit">5</span><span class="pun">)</span><span class="pln">

console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">t</span><span class="pun">.</span><span class="pln">length</span><span class="pun">)</span><span class="pln"> </span><span class="com">// 4</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">t</span><span class="pun">[</span><span class="lit">1</span><span class="pun">])</span><span class="pln">     </span><span class="com">// -1</span><span class="pln">

t</span><span class="pun">.</span><span class="pln">forEach</span><span class="pun">(</span><span class="pln">value </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">value</span><span class="pun">)</span><span class="pln">  </span><span class="com">// 1, -1, 3, 5</span><span class="pln">
</span><span class="pun">})</span><span class="pln">                    </span></pre>

<p>
	الأمر الملفت في هذه الشيفرة، هو إمكانية تعديل محتوى المصفوفة بالرغم من كونها ثابتة (const). ذلك أن المصفوفة عبارة عن كائن والمتغيّر سيشير إلى نفس الكائن دومًا حتى لو تغيّر محتواه بإضافة العناصر الجديدة. تستخدم تعليمة <code>forEach</code> كطريقة لتعداد عناصر المصفوفة في الشيفرة السابقة. حيث تمتلك <code>forEach</code> مُعاملًا على شكل دالة سهمية لها الصيغة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7064_11" style="">
<span class="pln">value </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">value</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تستدعي <code>forEach</code> الدالة من أجل كل عنصر من عناصر المصفوفة، وتمرر كل عنصر كمُعامل. يمكن للدالة التي تمثل مُعاملًا لتعليمة <code>forEach</code> أن تمتلك <a href="https://wiki.hsoub.com/JavaScript/Array/forEach" rel="external">مُعاملات أخرى</a> خاصة بها. كما استخدم التابع <a href="https://wiki.hsoub.com/JavaScript/Array/push" rel="external">push</a> لإضافة عنصر جديد إلى المصفوفة في المثال السابق. تستخدم عادة البرمجة بأسلوب الدوال (functional programming) مع React. ولهذا الأسلوب ميزة استخدام بنى المعطيات <a href="https://en.wikipedia.org/wiki/Immutable_object" rel="external nofollow">الصامدة</a> (Immutable). ويفضل عند كتابة شيفرة React استخدام التابع <a href="https://wiki.hsoub.com/JavaScript/Array#Array.prototype.concat.28.29.E2.80.8E" rel="external">concat</a>، فلا يضيف هذا التابع عنصرًا جديدًا إلى المصفوفة، بل ينشئ مصفوفة جديدة تضم محتويات القديمة بالإضافة إلى العنصر الجديد.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7064_13" style="">
<span class="kwd">const</span><span class="pln"> t </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">]</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> t2 </span><span class="pun">=</span><span class="pln"> t</span><span class="pun">.</span><span class="pln">concat</span><span class="pun">(</span><span class="lit">5</span><span class="pun">)</span><span class="pln">

console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">t</span><span class="pun">)</span><span class="pln">  </span><span class="com">// [1, -1, 3]</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">t2</span><span class="pun">)</span><span class="pln"> </span><span class="com">// [1, -1, 3, 5]</span></pre>

<p>
	لن يضيف الأمر <code>(t.concat(5</code> عنصرًا جديدًا إلى المصفوفة القديمة، بل سيعيد مصفوفة جديدة تضم العنصر الجديد (5) بالإضافة إلى عناصر المصفوفة القديمة. لقد عُرّفت الكثير من التوابع المفيدة للتعامل مع المصفوفات، فلنلقي نظرة على استخدام التابع <a href="https://wiki.hsoub.com/JavaScript/Array/map" rel="external">map</a> على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7064_15" style="">
<span class="kwd">const</span><span class="pln"> t </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">]</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> m1 </span><span class="pun">=</span><span class="pln"> t</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">value </span><span class="pun">=&gt;</span><span class="pln"> value </span><span class="pun">*</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">m1</span><span class="pun">)</span><span class="pln">   </span><span class="com">// [2, 4, 6]</span></pre>

<p>
	يُنشئ التابع <code>map</code> مصفوفةً جديدةً مبنيةً على أساس القديمة، وتستخدم الدالة التي مُررت كوسيط لإنشاء عناصر المصفوفة الجديدة. لاحظ في مثالنا السابق كيف نتجت العناصر الجديدة عن القديمة بضربها بالعدد 2. ويمكن للتابع <code>map</code> تحويل المصفوفة إلى شيءٍ مختلفٍ تمامًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7064_17" style="">
<span class="kwd">const</span><span class="pln"> m2 </span><span class="pun">=</span><span class="pln"> t</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">value </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="str">'&lt;li&gt;'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> value </span><span class="pun">+</span><span class="pln"> </span><span class="str">'&lt;/li&gt;'</span><span class="pun">)</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">m2</span><span class="pun">)</span><span class="pln">  
</span><span class="com">// [ '&lt;li&gt;1&lt;/li&gt;', '&lt;li&gt;2&lt;/li&gt;', '&lt;li&gt;3&lt;/li&gt;' ]</span></pre>

<p>
	لقد تحولّت المصفوفة المكوَّنة من أعداد صحيحة إلى مصفوفة تحوي عبارات HTML باستخدام <code>map</code>. سنستخدم هذا التابع بكثرة في React كما سنرى في القسم 2 لاحقًا. يمكن إسناد قيمة كل عنصر من المصفوفة إلى المتغيّرات بطريقة الإسناد بالتفكيك (<a href="https://wiki.hsoub.com/JavaScript#.D8.A7.D9.84.D8.A5.D8.B3.D9.86.D8.A7.D8.AF_.D8.A8.D8.A7.D9.84.D8.AA.D9.81.D9.83.D9.8A.D9.83" rel="external">destructuring assignment</a>).
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7064_19" style="">
<span class="kwd">const</span><span class="pln"> t </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">]</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">first</span><span class="pun">,</span><span class="pln"> second</span><span class="pun">,</span><span class="pln"> </span><span class="pun">...</span><span class="pln">rest</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> t

console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">first</span><span class="pun">,</span><span class="pln"> second</span><span class="pun">)</span><span class="pln">  </span><span class="com">// 1, 2</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">rest</span><span class="pun">)</span><span class="pln">          </span><span class="com">// [3, 4 ,5]</span></pre>

<p>
	"فُكّكت" عناصر المصفوفة <code>t</code> باستخدام الإسناد بالتفكيك، وأسند أول عنصرين منها إلى المتغيّرين <code>first</code> و<code>second</code>، ثم جُمّعت بقية عناصر المصفوفة في مصفوفة جديدة أسندت بدورها إلى المتغيّر <code>rest</code>.
</p>

<h2>
	الكائنات Objects
</h2>

<p>
	توجد طرق عدة لتعريف الكائنات في JavaScript، وأكثر هذه الطرق شيوعًا هي استخدام الشكل المختصر لتعريف الكائنات (<a href="https://wiki.hsoub.com/JavaScript/Object" rel="external">object literals</a>) والتي تُنشأ بوضع خصائصها على شكل قائمة عناصر تفصل بينها الفواصل بين قوسين معقوصين.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7064_21" style="">
<span class="kwd">const</span><span class="pln"> object1 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Arto Hellas'</span><span class="pun">,</span><span class="pln">
  age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">35</span><span class="pun">,</span><span class="pln">
  education</span><span class="pun">:</span><span class="pln"> </span><span class="str">'PhD'</span><span class="pun">,</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> object2 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Full Stack web application development'</span><span class="pun">,</span><span class="pln">
  level</span><span class="pun">:</span><span class="pln"> </span><span class="str">'intermediate studies'</span><span class="pun">,</span><span class="pln">
  size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> object3 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    first</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Dan'</span><span class="pun">,</span><span class="pln">
    last</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Abramov'</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  grades</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">],</span><span class="pln">
  department</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Stanford University'</span><span class="pun">,</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تأخذ الخصائص قيمًا من أي نوع مثل الصحيحة والنصية والمصفوفات والكائنات، وتعرّف خصائص كائن ما باستخدام النقطة "." أو باستخدام الأقواس المعقوفة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7064_23" style="">
<span class="pln">console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">object1</span><span class="pun">.</span><span class="pln">name</span><span class="pun">)</span><span class="pln">         </span><span class="com">// Arto Hellas</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> fieldName </span><span class="pun">=</span><span class="pln"> </span><span class="str">'age'</span><span class="pln"> 
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">object1</span><span class="pun">[</span><span class="pln">fieldName</span><span class="pun">])</span><span class="pln">    </span><span class="com">// 35</span></pre>

<p>
	كما تُضاف الخصائص إلى الكائن مباشرة باستخدام النقطة "." أو الأقواس المعقوفة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7064_25" style="">
<span class="pln">object1</span><span class="pun">.</span><span class="pln">address </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Helsinki'</span><span class="pln">
object1</span><span class="pun">[</span><span class="str">'secret number'</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">12341</span></pre>

<p>
	لقد توجب علينا استخدام الأقواس المعقوفة عند إضافة الخاصية الأخيرة، ذلك أن الاسم (secret number) لا يصلح اسمًا لخاصية نظرًا لوجود فراغ بين الكلمتين. تمتلك الكائنات في JavaScript توابعًا أيضًا، لكننا لن نستخدم في المنهاج كائنات لها توابعها الخاصة، وسنكتفي بمناقشتها بإيجاز خلال تقدمنا. تُعرّف الكائنات أيضًا باستخدام الدوال البانية (constructor functions) التي تشابه في آلية عملها مثيلاتها في لغات برمجة أخرى، كدوال البناء في صفوف Java. مع ذلك، لا تمتلك JavaScript صفوفًا بالمفهوم الذي نراه في البرمجة كائنية التوجه (<abbr title="Object-Oriented Programming | البرمجة كائنية التوجه">OOP</abbr>). أضيفت الصيغة <code>class</code> للغة JavaScript ابتداء من النسخة ES6، والتي تساعد في بعض الحالات على بناء صفوف كائنية التوجه.
</p>

<h2>
	الدوال Functions
</h2>

<p>
	تعرّفنا سابقًا على استخدام التوابع السهمية والتي تُكتب بصيغتها الكاملة على النحو:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7064_27" style="">
<span class="kwd">const</span><span class="pln"> sum </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">p1</span><span class="pun">,</span><span class="pln"> p2</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">p1</span><span class="pun">)</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">p2</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> p1 </span><span class="pun">+</span><span class="pln"> p2
</span><span class="pun">}</span></pre>

<p>
	وتُستدعى كما هو متوقع على النحو:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7064_29" style="">
<span class="kwd">const</span><span class="pln"> result </span><span class="pun">=</span><span class="pln"> sum</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">)</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">result</span><span class="pun">)</span></pre>

<p>
	يمكن تجاهل كتابة الأقواس المحيطة بالمُعاملات إن كان للدالة مُعامل واحد:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7064_32" style="">
<span class="kwd">const</span><span class="pln"> square </span><span class="pun">=</span><span class="pln"> p </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">p</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> p </span><span class="pun">*</span><span class="pln"> p
</span><span class="pun">}</span></pre>

<p>
	وإن احتوت الدالة على عبارة برمجية واحدة، لا حاجة عندها لاستخدام الأقواس المعقوصة، وستعيد الدالة القيمة الناتجة عن تنفيذ هذه العبارة. لاحظ كيف سيُختصر تعريف الدالة لو أزلنا العبارة التي تطبع النتيجة على الطرفية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7064_34" style="">
<span class="kwd">const</span><span class="pln"> square </span><span class="pun">=</span><span class="pln"> p </span><span class="pun">=&gt;</span><span class="pln"> p </span><span class="pun">*</span><span class="pln"> p</span></pre>

<p>
	ولهذا الشكل أهميته التطبيقية عندما نتعامل مع المصفوفات وخاصة باستعمال التابع <code>map</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7064_37" style="">
<span class="kwd">const</span><span class="pln"> t </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">]</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> tSquared </span><span class="pun">=</span><span class="pln"> t</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">p </span><span class="pun">=&gt;</span><span class="pln"> p </span><span class="pun">*</span><span class="pln"> p</span><span class="pun">)</span><span class="pln">
</span><span class="com">// tSquared is now [1, 4, 9]</span></pre>

<p>
	أضيفت الدوال السهمية إلى JavaScript مع النسخة ES6 منذ سنتين تقريبًا. وقد عُرّفت الدوال قبل ذلك بالكلمة <code>function</code> فقط. وعمومًا هناك طريقتان لتعريف الدوال، الأولى <strong>تسمية الدالة بالتصريح عنها</strong> (<a href="https://wiki.hsoub.com/JavaScript/function" rel="external">function declaration</a>):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7064_39" style="">
<span class="kwd">function</span><span class="pln"> product</span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> a </span><span class="pun">*</span><span class="pln"> b
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> result </span><span class="pun">=</span><span class="pln"> product</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6</span><span class="pun">)</span><span class="pln">
</span><span class="com">// result is now 12</span></pre>

<p>
	أما الطريقة الثانية فهي استخدام <strong>تعبير تعريف دالة</strong> (<a href="https://wiki.hsoub.com/JavaScript/Function_Expression" rel="external">function expression</a>)، وفي هذه الحالة لا داع لإعطاء الدالة اسمًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7064_41" style="">
<span class="kwd">const</span><span class="pln"> average </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a </span><span class="pun">+</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> result </span><span class="pun">=</span><span class="pln"> average</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">)</span><span class="pln">
</span><span class="com">// result is now 3.5</span></pre>

<p>
	سنستخدم في هذا المنهاج الدوال السهمية دائمًا.
</p>

<h2>
	التمارين 1.3- 1.5
</h2>

<p>
	سنكمل بناء التطبيق الذي بدأناه سابقًا، لهذا يمكنك متابعة كتابة الشيفرة في نفس المشروع طالما أن المهم هو الحالة النهائية للتطبيق الذي ستسلّمه.
</p>

<p>
	<strong>نصيحة للاحتراف</strong>: قد تواجهك عقبات تتعلق ببنية الخصائص التي تمتلكها المكوِّنات. اجعل الأمر أكثر وضوحًا بطباعة الخصائص على الطرفية كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7064_44" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Header</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln">  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">course</span><span class="pun">}&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">}</span></pre>

<h3>
	1.3 معلومات عن المنهاج: الخطوة 3
</h3>

<p>
	سنمضي قدمًا نحو الأمام مستخدمين الكائنات في تطبيقنا. عدّل تعريف المتغيّر في المكوّن App بالشكل التالي وأعد صياغة التطبيق حتى يبقى قابلًا للتنفيذ:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7064_46" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> course </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Half Stack application development'</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> part1 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Fundamentals of React'</span><span class="pun">,</span><span class="pln">
    exercises</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> part2 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Using props to pass data'</span><span class="pun">,</span><span class="pln">
    exercises</span><span class="pun">:</span><span class="pln"> </span><span class="lit">7</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> part3 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'State of a component'</span><span class="pun">,</span><span class="pln">
    exercises</span><span class="pun">:</span><span class="pln"> </span><span class="lit">14</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">...</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<h3>
	1.4 معلومات عن المنهاج: الخطوة 4
</h3>

<p>
	ضع بعد ذلك الكائنات في مصفوفة. عدّل تعريف المتغيّر في المكوِّن App إلى الشكل التالي ولا تنس تعديل بقية الأجزاء في المكوِّن بما يتوافق معه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7064_48" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> course </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Half Stack application development'</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> parts </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
      name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Fundamentals of React'</span><span class="pun">,</span><span class="pln">
      exercises</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
      name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Using props to pass data'</span><span class="pun">,</span><span class="pln">
      exercises</span><span class="pun">:</span><span class="pln"> </span><span class="lit">7</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
      name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'State of a component'</span><span class="pun">,</span><span class="pln">
      exercises</span><span class="pun">:</span><span class="pln"> </span><span class="lit">14</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">]</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">...</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	<strong>ملاحظة</strong>: اعتبر حتى هذه اللحظة أن هناك ثلاثة عناصر فقط ضمن المصفوفة لذلك لا ضرورة لاستخدام الحلقات عند التنقل بين العناصر. سنعود لاحقًا بتفصيل أعمق إلى موضوع تصيير الكائنات المبنية من عناصر مصفوفة في القسم التالي. لاتُمرِّر كائنات مختلفة على شكل خصائص من المكوِّن App إلى المكوِّنين Content و Total، بل مررها مباشرة كمصفوفة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7064_50" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// const definitions</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Header</span><span class="pln"> course</span><span class="pun">={</span><span class="pln">course</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Content</span><span class="pln"> parts</span><span class="pun">={</span><span class="pln">parts</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Total</span><span class="pln"> parts</span><span class="pun">={</span><span class="pln">parts</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<h3>
	1.5 معلومات عن المنهاج: الخطوة 5
</h3>

<p>
	لنتقدم خطوة أخرى إلى الأمام. حوّل المنهاج وأقسامه إلى كائن JavaScript واحد، وأصلح كل ما يتضرر:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7064_52" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> course </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Half Stack application development'</span><span class="pun">,</span><span class="pln">
    parts</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">
        name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Fundamentals of React'</span><span class="pun">,</span><span class="pln">
        exercises</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">
        name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Using props to pass data'</span><span class="pun">,</span><span class="pln">
        exercises</span><span class="pun">:</span><span class="pln"> </span><span class="lit">7</span><span class="pln">
      </span><span class="pun">},</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">
        name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'State of a component'</span><span class="pun">,</span><span class="pln">
        exercises</span><span class="pun">:</span><span class="pln"> </span><span class="lit">14</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">]</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">...</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	توابع الكائنات والمؤشر "this"
</h2>

<p>
	لن نستخدم كما ذكرنا سابقًا كائنات لها توابعها الخاصة، ذلك أننا سنعتمد على نسخة من React تدعم <a href="https://wiki.hsoub.com/React#.D8.A7.D9.84.D8.AE.D8.B7.D8.A7.D9.81.D8.A7.D8.AA" rel="external">الخطافات</a>. لن تجد فيما سيأتي لاحقًا في هذا الفصل ما يتعلق بالمنهاج، لكن من الجيد الاطلاع على المعلومات الواردة وفهمها وخاصة عندما تستخدم نسخًا أقدم من React.
</p>

<p>
	يختلف سلوك الدوال السهمية عن تلك المعرّفة باستخدام التصريح <code>function</code> فيما يتعلق باستخدام الكلمة <a href="https://wiki.hsoub.com/JavaScript/this" rel="external">this</a> التي تشير إلى الكائن نفسه. من الممكن إسناد التوابع إلى كائن بتعريف بعض خصائصه على شكل دوال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7064_54" style="">
<span class="kwd">const</span><span class="pln"> arto </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Arto Hellas'</span><span class="pun">,</span><span class="pln">
  age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">35</span><span class="pun">,</span><span class="pln">
  education</span><span class="pun">:</span><span class="pln"> </span><span class="str">'PhD'</span><span class="pun">,</span><span class="pln">
  greet</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'hello, my name is '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">)</span><span class="pln">  </span><span class="pun">},}</span><span class="pln">

arto</span><span class="pun">.</span><span class="pln">greet</span><span class="pun">()</span><span class="pln">  </span><span class="com">// "hello, my name is Arto Hellas"</span></pre>

<p>
	وقد تسند التوابع إلى الكائنات حتى بعد إنشاء هذه الكائنات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7064_56" style="">
<span class="kwd">const</span><span class="pln"> arto </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Arto Hellas'</span><span class="pun">,</span><span class="pln">
  age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">35</span><span class="pun">,</span><span class="pln">
  education</span><span class="pun">:</span><span class="pln"> </span><span class="str">'PhD'</span><span class="pun">,</span><span class="pln">
  greet</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'hello, my name is '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

arto</span><span class="pun">.</span><span class="pln">growOlder </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">age </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">}</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">arto</span><span class="pun">.</span><span class="pln">age</span><span class="pun">)</span><span class="pln">   </span><span class="com">// 35 is printed</span><span class="pln">
arto</span><span class="pun">.</span><span class="pln">growOlder</span><span class="pun">()</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">arto</span><span class="pun">.</span><span class="pln">age</span><span class="pun">)</span><span class="pln">   </span><span class="com">// 36 is printed</span></pre>

<p>
	لنعدّل الكائن كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7064_58" style="">
<span class="kwd">const</span><span class="pln"> arto </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Arto Hellas'</span><span class="pun">,</span><span class="pln">
  age</span><span class="pun">:</span><span class="pln"> </span><span class="lit">35</span><span class="pun">,</span><span class="pln">
  education</span><span class="pun">:</span><span class="pln"> </span><span class="str">'PhD'</span><span class="pun">,</span><span class="pln">
  greet</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'hello, my name is '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  doAddition</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">a </span><span class="pun">+</span><span class="pln"> b</span><span class="pun">)</span><span class="pln">  </span><span class="pun">},}</span><span class="pln">

arto</span><span class="pun">.</span><span class="pln">doAddition</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">)</span><span class="pln">        </span><span class="com">// 5 is printed</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> referenceToAddition </span><span class="pun">=</span><span class="pln"> arto</span><span class="pun">.</span><span class="pln">doAddition
referenceToAddition</span><span class="pun">(</span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </span><span class="lit">15</span><span class="pun">)</span><span class="pln">   </span><span class="com">// 25 is printed</span></pre>

<p>
	يمتلك الكائن الآن التابع <code>doAddition</code> الذي يجمع الأعداد التي تمرر إليه كوسطاء. يستدعى هذا التابع بالطريقة التقليدية <code>(arto.doAddition(1, 4</code>، أو بإسناد مرجعٍ للتابع إلى متغّير ومن ثم استدعاءه من خلال المتغيّر كما هو الحال في السطرين الأخيرين من الشيفرة السابقة. لكن لو حاولنا استخدام الطريقة ذاتها مع التابع <code>greet</code> سنواجه مشكلة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7064_60" style="">
<span class="pln">arto</span><span class="pun">.</span><span class="pln">greet</span><span class="pun">()</span><span class="pln">       </span><span class="com">// "hello, my name is Arto Hellas"</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> referenceToGreet </span><span class="pun">=</span><span class="pln"> arto</span><span class="pun">.</span><span class="pln">greet
referenceToGreet</span><span class="pun">()</span><span class="pln"> </span><span class="com">// "hello, my name is undefined"</span></pre>

<p>
	فعندما نستدعي التابع باستخدام مرجع لكائن، سيفقد التابع القدرة على تحديد الكائن الذي تشير إليه الكلمة <code>this</code>. وعلى نقيض بقية اللغات، تُحدّد قيمة <a href="https://wiki.hsoub.com/JavaScript/this" rel="external">this</a> في JavaScript وفقًا للطريقة التي يُستدعى بها التابع. فعندما تُستدعى من خلال مرجع تتحول <code>this</code> إلى كائن عام (<a href="https://wiki.hsoub.com/JavaScript/Object" rel="external">global object</a>) ولن تكون النتيجة ما يريده المطوّر في أغلب الأوقات. تقودنا الحالة السابقة لمواجهة العديد من المشاكل وخاصة عندما تحاول React أو Node استدعاء توابع عرفها المطوّر للكائن. لذلك سنتغلب على هذه العقبة بكتابة شيفرة JavaScript لا تستعمل <code>this</code>. لكن هناك حالة خاصة تظهر عندما نحاول ضبط قيمة انتهاء الوقت (timeout) للدالة <code>greet</code> التي تمثل جزءًا من اللكائن <code>arto</code> باستخدام <a href="https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout" rel="external nofollow">setTimeout</a>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7064_62" style="">
<span class="kwd">const</span><span class="pln"> arto </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Arto Hellas'</span><span class="pun">,</span><span class="pln">
  greet</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'hello, my name is '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

setTimeout</span><span class="pun">(</span><span class="pln">arto</span><span class="pun">.</span><span class="pln">greet</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">)</span></pre>

<p>
	تُحدّد قيمة <code>this</code> في JavaScript وفقًا للطريقة التي يُستدعى بها التابع كما أشرنا سابقًا. فعندما نستخدم الدالة <code>setTimeout</code> لاستدعاء تابع، فإن محرك JavaScript هو من يستدعى التابع حقيقةً، وستشير <code>this</code> عندها إلى كائن عام. هناك آليات عديدة للاحتفاظ بمرجع <code>this</code> الأصلي، منها استدعاء الدالة <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind" rel="external nofollow">bind</a> كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7064_64" style="">
<span class="pln">setTimeout</span><span class="pun">(</span><span class="pln">arto</span><span class="pun">.</span><span class="pln">greet</span><span class="pun">.</span><span class="pln">bind</span><span class="pun">(</span><span class="pln">arto</span><span class="pun">),</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">)</span></pre>

<p>
	سينشئ الاستدعاء <code>(arto.greet.bind(arto</code> دالة جديدة تشير فيها <code>this</code> إلى <code>Arto</code> بصرف النظر عن الطريقة التي تم بها استدعاء التابع. تُستخدم الدوال السهمية في بعض الأحيان لحل بعض مشاكل <code>this</code>. لكن لا ينبغي استخدام هذه الدوال كتوابع لكائنات، لأن <code>this</code> لن تعمل عندها أبدًا. سنعرّج لاحقًا على توضيح سلوك <code>this</code> مع الدوال السهمية. تمتلئ صفحات الانترنت بمعلومات عن استخدام <code>this</code> في JavaScript، إن أردت فهم ذلك أكثر، نوصيك بشدة متابعة سلسة <a href="https://egghead.io/courses/understand-javascript-s-this-keyword-in-depth" rel="external nofollow">Understand JavaScript's this Keyword in Depth</a> التي أعدها <a href="https://egghead.io/" rel="external nofollow">egghead.io</a> على سبيل المثال.
</p>

<h2>
	الأصناف Classes
</h2>

<p>
	لا تمتلك JavaScript كما أشرنا سابقًا صفوفًا تشابه تلك التي تقدمها اللغات كائنية التوجه. لكنها تمتلك ميزات تمكّننا من محاكاة تلك <a href="https://wiki.hsoub.com/JavaScript/class" rel="external">الأصناف</a>. لنلق نظرة سريعة على الصيغة <code>class</code> التي قدمتها النسخة ES6 والتي تبسّط تعريف الأصناف (أو الأغراض الشبيه بالأصناف). سنعرّف في المثال التالي صفًا يسمى Person وكائنين Person:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7064_66" style="">
<span class="kwd">class</span><span class="pln"> </span><span class="typ">Person</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  constructor</span><span class="pun">(</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> age</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name </span><span class="pun">=</span><span class="pln"> name
    </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">age </span><span class="pun">=</span><span class="pln"> age
  </span><span class="pun">}</span><span class="pln">
  greet</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'hello, my name is '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">name</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> adam </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Person</span><span class="pun">(</span><span class="str">'Adam Ondra'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">35</span><span class="pun">)</span><span class="pln">
adam</span><span class="pun">.</span><span class="pln">greet</span><span class="pun">()</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> janja </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Person</span><span class="pun">(</span><span class="str">'Janja Garnbret'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">22</span><span class="pun">)</span><span class="pln">
janja</span><span class="pun">.</span><span class="pln">greet</span><span class="pun">()</span></pre>

<p>
	تتشابه الأصناف والكائنات الناتجة من الناحية التعبيرية (Syntax) مع تلك التي تقدمها Java، كما تتشابه من ناحية السلوك أيضًا. لكنها تبقى في الصميم كائنات ناتجة عن وراثة نماذج أولية (<a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Inheritance" rel="external nofollow">prototypal inheritance</a>) تقدمها JavaScript. فنمط كلٍّ من الكائنين عمليًا هو <code>Object</code>، لأن JavaScript تعرّف افتراضيًا أنواع البيانات الأساسية التالية: Boolean و Null و Undefined و Number و String و Symbol و Object فقط. على أية حال كان تقديم الصيغة <code>class</code> محط خلاف، يمكنك القراءة أكثر عن ذلك في المقالة <a href="https://github.com/petsel/not-awesome-es6-classes" rel="external nofollow">Not Awesome: ES6 Classes</a> أو في المقالة <a href="https://medium.com/@rajaraodv/is-class-in-es6-the-new-bad-part-6c4e6fe1ee65" rel="external nofollow">?Is “Class” In ES6 The New “Bad” Part</a>. لقد استخدمت هذه الصيغة مرارًا في النسخ القديمة من React وكذلك في Node.js، لكننا لن نستخدمها في المنهاج كبنية أساسية، طالما أننا سنستخدم ميزة الخطافات الجديدة في React.
</p>

<h2>
	مواد إضافية لتعلم JavaScript
</h2>

<p>
	تقدم أكاديمية حسوب <a href="https://academy.hsoub.com/programming/javascript/" rel="">توثيقًا عربيًا شاملًا</a> مترجمًا عن الموقع <a href="https://javascript.info/" rel="external nofollow">javascript.info</a> وننصح بشدة الاطلاع على كل المقالات الموجودة. بالإضافة إلى ذلك ستجد على شبكة الانترنت الكثير من المواد المتعلقة باللغة منها الجيد ومنها السيء، فيمكنك الاطلاع على المراجع التي تقدمها شركة Mozilla والمتعلقة بميزات JavaScript من خلال الدليل <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript" rel="external nofollow">Mozilla's Javascript Guide</a>. كما نوصيك بشدة أن تتطلع مباشرة على الدورة التعليمية <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript" rel="external nofollow">A re-introduction to JavaScript JS tutorial</a> على موقع الويب لشركة Mozilla. إن أردت التعمق بهذه اللغة نوصيك بسلسلة كتب مجانية ممتازة على الإنترنت تدعى <a href="https://github.com/getify/You-Dont-Know-JS" rel="external nofollow">You-Dont-Know-JS</a>. يعتبر الموقع <a href="https://egghead.io/" rel="external nofollow">egghead.io</a> مرجعًا جيدًا حيث يضم شروحات قيّمة عن JavaScript وعن React وغيرها من المواضيع الهامة، لكن ليست جميع المواد الموجودة مجانية.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://fullstackopen.com/en/part1/java_script" rel="external nofollow">JavaScript</a> من سلسلة <a href="https://fullstackopen.com/en/" rel="external nofollow">Deep Dive Into Modern Web Development</a>
</p>
]]></description><guid isPermaLink="false">1073</guid><pubDate>Sun, 15 Nov 2020 13:00:00 +0000</pubDate></item><item><title>&#x645;&#x62F;&#x62E;&#x644; &#x625;&#x644;&#x649; React</title><link>https://academy.hsoub.com/programming/javascript/react/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-react-r1072/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2020_11/1.png.3566df3373e7114d3ed681843b7cf342.png" /></p>

<p>
	سنتعرف فيما سيأتي على أهم موضوع في هذا المنهاج، بالتحديد على مكتبة <a href="https://reactjs.org/" rel="external nofollow">React</a>. لنبدأ إذًا بكتابة تطبيق بسيط يمهد الطريق لفهم المبادئ الأساسية لهذه المكتبة. سنستعمل الأداة <a href="https://github.com/facebook/create-react-app" rel="external nofollow">create-react-app</a> التي ستسهل علينا كثيرا التعامل مع الملفات الأساسية لمشروع React، فمن الممكن تثبيت هذه الأداة على حاسوبك طالما أن نسخة الأداة npm التي ثُبِّتت مع Node على الأقل 5.3، وبالطبع يبقى موضوع استخدام هذه الأداة اختيارًا شخصيًا. لننشئ الآن تطبيقًا باسم (Part1) ولننتقل إلى المجلد الذي يضم هذا التطبيق من خلال تنفيذ الشيفرة التالية:
</p>

<pre class="ipsCode">
$ npx create-react-app part1
$ cd part1
</pre>

<p>
	سيبدأ كل سطر في هذا التطبيق وفي كل تطبيق بالرمز $ ضمن واجهة الطرفية. لن تضطر إلى كتابة هذا الرمز باستمرار لأنه في الواقع سيمثل مَحثَّ سطر الأوامر. سنشغل التطبيق بكتابة الأمر التالي:
</p>

<pre class="ipsCode">
$ npm start
</pre>

<p>
	سيعمل التطبيق بشكل افتراضي على الخادم المحلي (LocalHost) لجهازك عند المنفذ (Port) رقم 3000 وعلى العنوان <a href="http://localhost:3000/" rel="external nofollow">http://localhost:3000</a> وسيفتح متصفحك الافتراضي آليًا صفحة الويب. افتح طرفية المتصفح مباشرةً وافتح أيضًا محرر نصوص لتتمكن من عرض الشيفرة وصفحة الويب في نفس الوقت على شاشتك.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="53789" href="https://academy.hsoub.com/uploads/monthly_2020_11/create_react_app_console_001.png.bd015b81d150aa060222389a63caaa22.png" rel=""><img alt="create_react_app_console_001.png" class="ipsImage ipsImage_thumbnailed" data-fileid="53789" data-unique="s4q1diiel" src="https://academy.hsoub.com/uploads/monthly_2020_11/create_react_app_console_001.png.bd015b81d150aa060222389a63caaa22.png"></a>
</p>

<p>
	يحتوي المجلد src على شيفرة التطبيق. سنبسِّط شيفرة التطبيق المكتوبة في الملف index.js التي ستظهر كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8215_8" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">ReactDOM</span><span class="pln"> from </span><span class="str">'react-dom'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="typ">Hello</span><span class="pln"> world</span><span class="pun">&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">)</span><span class="pln">

</span><span class="typ">ReactDOM</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(&lt;</span><span class="typ">App</span><span class="pln"> </span><span class="pun">/&gt;,</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'root'</span><span class="pun">))</span></pre>

<p>
	يمكنك حذف الملفات التالية فلن تحتاجها حاليًا في التطبيق:
</p>

<ul>
<li>
		App.js
	</li>
	<li>
		App.css
	</li>
	<li>
		App.test.js
	</li>
	<li>
		logo.svg
	</li>
	<li>
		setupTests.js
	</li>
	<li>
		service Worker.js
	</li>
</ul>
<h2>
	المكوِّنات Components
</h2>

<p>
	يعّرف الملف index.js <a href="https://reactjs.org/docs/components-and-props.html" rel="external nofollow">مكوّنَ React</a> يدعى App، سيصيّره السطر الأخير من الشيفرة إلى عنصر<code>div</code> الذي ستجده معرفًا في الملف public/index.html ويحمل القيمة "root" في الخاصية <code>id</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8215_10" style="">
<span class="typ">ReactDOM</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(&lt;</span><span class="typ">App</span><span class="pln"> </span><span class="pun">/&gt;,</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'root'</span><span class="pun">))</span></pre>

<p>
	ستجد ملف html السابق فارغًا بشكل افتراضي، حيث يمكنك إضافة ما تشاء من شيفرة html إليه. لكن طالما أننا نستخدم الآن React، فكل المحتوى الذي سيصيَّر ستجده معرّفًا على شكل مكوِّنات React. لنلق نظرة أقرب على الشيفرة التي تعرّف المكوِّن:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8215_12" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="typ">Hello</span><span class="pln"> world</span><span class="pun">&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">)</span></pre>

<p>
	إن كان تخمينك صحيحًا، سيُصيَّر المكوِّن إلى عنصر<code>div</code> يضم عنصر<code>p</code> يحوي داخله العبارة "Hello Word". في الواقع عُرّف المكوِّن على شكل دالة JavaScript، فتمثل الشيفرة التالية دالة لا تمتلك أية مُعاملات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8215_14" style="">
<span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="typ">Hello</span><span class="pln"> world</span><span class="pun">&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">)</span></pre>

<p>
	ثم تُسند الدالة بعدها إلى متغيّر ثابت القيمة (Constant Variable) يدعى App:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8215_18" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">...</span></pre>

<p>
	تُعرّف الدوال في JavaScript بطرق عدة، سنستخدم هنا <a href="https://academy.hsoub.com/programming/javascript/%D9%86%D8%B8%D8%B1%D8%A9-%D8%AA%D9%81%D8%B5%D9%8A%D9%84%D9%8A%D8%A9-%D8%B9%D9%84%D9%89-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D8%A7%D9%84%D8%B3%D9%87%D9%85%D9%8A%D8%A9-arrow-functions-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r880/" rel="">الدوال السهمية</a> التي وصِّفت في النسخ الأحدث من JavaScript تحت عنوان <a href="http://es6-features.org/#Constants" rel="external nofollow">ECMAScript 6</a> والذي يدعى أيضًا ES6. ونظرًا لاحتواء الدالة على عبارة وحيدة، فقد استخدمنا طريقة مختصرة في تمثيلها كما تظهرها الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8215_20" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="typ">Hello</span><span class="pln"> world</span><span class="pun">&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لاحظ أنّ الدالة قد أعادت قيمة العبارة التي احتوتها. قد تحتوي الدالة التي تعرِّف المكوِّن أية شيفرة مكتوبة بلغة JavaScript. عدِّل الشيفرة لتصبح على النحو التالي وراقب ما الذي سيتغير على شاشة الطرفية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8215_22" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'Hello from component'</span><span class="pun">)</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="typ">Hello</span><span class="pln"> world</span><span class="pun">&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	من الممكن أيضًا تصيير المحتويات الديناميكية إن وجدت داخل المكوِّن، عدِّل الشيفرة لتصبح كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8215_24" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> now </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">()</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> a </span><span class="pun">=</span><span class="pln"> </span><span class="lit">10</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> b </span><span class="pun">=</span><span class="pln"> </span><span class="lit">20</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="typ">Hello</span><span class="pln"> world</span><span class="pun">,</span><span class="pln"> it is </span><span class="pun">{</span><span class="pln">now</span><span class="pun">.</span><span class="pln">toString</span><span class="pun">()}&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">a</span><span class="pun">}</span><span class="pln"> plus </span><span class="pun">{</span><span class="pln">b</span><span class="pun">}</span><span class="pln"> is </span><span class="pun">{</span><span class="pln">a </span><span class="pun">+</span><span class="pln"> b</span><span class="pun">}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تُنفَّذ شيفرة JavaScript الموجودة داخل الأقواس المعقوصة (curly braces) وتظهر نتيجتها ضمن أسطر HTML التي يولدها المكوِّن.
</p>

<h2>
	JSX
</h2>

<p>
	يبدو للوهلة الأولى أن مكوِّنات React تعيد شيفرة HTML، لكن ليس تمامًا. تُصمم مكوِّنات React غالبًا باستخدام <a href="https://wiki.hsoub.com/React/introducing_jsx" rel="external">JSX</a>. قد تبدو JSX شبيهة بتنسيق HTML، لكنها في الواقع مجرد طريقة لكتابة JavaScript وستعيد المكوِّنات شيفرة JSX وقد ترجمت إلى JavaScript. سيبدو التطبيق الذي نعمل عليه بالشكل التالي بعد ترجمته:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8215_26" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">ReactDOM</span><span class="pln"> from </span><span class="str">'react-dom'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> now </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">()</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> a </span><span class="pun">=</span><span class="pln"> </span><span class="lit">10</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> b </span><span class="pun">=</span><span class="pln"> </span><span class="lit">20</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">React</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="pln">
    </span><span class="str">'div'</span><span class="pun">,</span><span class="pln">
    </span><span class="kwd">null</span><span class="pun">,</span><span class="pln">
    </span><span class="typ">React</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="pln">
      </span><span class="str">'p'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Hello world, it is '</span><span class="pun">,</span><span class="pln"> now</span><span class="pun">.</span><span class="pln">toString</span><span class="pun">()</span><span class="pln">
    </span><span class="pun">),</span><span class="pln">
    </span><span class="typ">React</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="pln">
      </span><span class="str">'p'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">,</span><span class="pln"> a</span><span class="pun">,</span><span class="pln"> </span><span class="str">' plus '</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">,</span><span class="pln"> </span><span class="str">' is '</span><span class="pun">,</span><span class="pln"> a </span><span class="pun">+</span><span class="pln"> b
    </span><span class="pun">)</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="typ">ReactDOM</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(</span><span class="pln">
  </span><span class="typ">React</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="typ">App</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">),</span><span class="pln">
  document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'root'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">)</span></pre>

<p>
	تُرجم التطبيق باستخدام <a href="https://babeljs.io/repl/" rel="external nofollow">Babel</a>. تترجم المشاريع التي أُنشئت باستخدام create-react-app أليًا، وسنطّلع أكثر على هذا الموضوع في القسم 7 من هذا المنهاج. من الممكن أيضًا كتابة تطبيقات React مستخدمين شيفرة JavaScript صرفة دون اعتماد JSX، لكن لن يرغب أحد بفعل ذلك.
</p>

<p>
	تتشابه من الناحية العملية كل من JSX و HTML، ويكمن الاختلاف البسيط بينهما في سهولة إدراج شيفرة JavaScript ضمن أقواس معقوصة وتنفيذها ضمن JSX. إن فكرة JSX مشابهة لفكرة العديد من اللغات التي تعتمد على القوالب مثل لغة Thymeleaf التي تستخدم مع Java Spring على الخادم. وهي تشابه <a href="https://developer.mozilla.org/en-US/docs/Web/XML/XML_introduction" rel="external nofollow">XML</a> في أن معرِّفي البداية والنهاية لكل عنصر يجب أن يكونا موجودين. فعلى سبيل المثال يمكن كتابة عنصر السطر الجديد <code>&lt;br&gt;</code> في HTML على النحو:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8215_28" style="">
<span class="tag">&lt;br&gt;</span></pre>

<p>
	لكن عندما نستخدم JSX، لابد من إغلاق العنصر أي وضع معرِّف النهاية كالتالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8215_30" style="">
<span class="tag">&lt;br</span><span class="pln"> </span><span class="tag">/&gt;</span></pre>

<h2>
	المكوّنات المتعددة
</h2>

<p>
	سنعدّل شيفرة التطبيق على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8215_32" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Hello</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="typ">Hello</span><span class="pln"> world</span><span class="pun">&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Greetings</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Hello</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">    
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="typ">ReactDOM</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(&lt;</span><span class="typ">App</span><span class="pln"> </span><span class="pun">/&gt;,</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'root'</span><span class="pun">))</span></pre>

<p>
	<strong>انتبه</strong>: لم ندرج الملفات الرأسية (الملفات المدرجة باستخدام تعليمة <code>import</code>) في الشيفرة المعروضة سابقًا ولن نفعل في المستقبل، لكن عليك إدراجها دائمًا عندما تحاول تشغيل التطبيق.
</p>

<p>
	عرّفنا داخل المكوّن App مكوِّنًا جديدًا يدعى Hello استُخدم أكثر من مرة ويعتبر ذلك أمرًا طبيعيًًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8215_34" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Greetings</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Hello</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Hello</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">      
      </span><span class="pun">&lt;</span><span class="typ">Hello</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	من السهل إنشاء المكوِّنات في React، وبضم المكوِّنات إلى بعضها ستنتج تطبيقات أكثر تعقيدًا لكنها مع ذلك تبقى قابلة للتنفيذ. إنها فلسفة React التي تعتمد في جوهرها على بناء التطبيقات باستخدام مكوِّنات لها أغراض محددة يمكن إعادة استخدامها في أي وقت.
</p>

<p>
	تعتبر فكرة المكوّن الجذري (root component) الذي يمثله هنا App (المكوّن الذي يقع أعلى شجرة المكوِّنات)، نقطة قوة أخرى في React. مع ذلك سنجد في القسم 6 أنّ هذا المكوّن لن يكون جذريًّا تمامًا، لكنه سيُغلَّف ضمن مكوِّن تخديمي (utility component) مناسب.
</p>

<h2>
	الخصائص (Props): تمرير البيانات إلى المكوِّنات
</h2>

<p>
	من الممكن تمرير البيانات إلى المكوّنات مستخدمين مايسمى <a href="https://wiki.hsoub.com/React/components_and_props" rel="external">الخصائص</a> (Props). سنعدّل المكوِّن Hello كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8215_38" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Hello</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="typ">Hello</span><span class="pln"> </span><span class="pun">{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">name</span><span class="pun">}&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تمتلك الدالة التي تعرّف المكوِّن Hello مُعاملًا يدعى props. يستقبل المُعامل (الذي يلعب دور الوسيط هنا) كائنًا يمتلك حقولًا تمثل كل الخصائص التي عُرِّفت في المكوّن. سنستعرض ذلك من خلال الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8215_40" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Greetings</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Hello</span><span class="pln"> name</span><span class="pun">=</span><span class="str">"George"</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Hello</span><span class="pln"> name</span><span class="pun">=</span><span class="str">"Daisy"</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لا يوجد عدد محدد من الخصائص لمكوّن ما، ويمكن أن تحمل هذه الخصائص نصوصًا جاهزةً (hard coded) أو قيمًا ناتجة عن تنفيذ عبارات JavaScript. ينبغي وضع قيم الخصائص الناتجة عن تنفيذ تلك العبارات ضمن أقواس معقوصة. سنعدل شيفرة المكوّن Hello ليمتلك خاصيتين كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8215_42" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Hello</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="typ">Hello</span><span class="pln"> </span><span class="pun">{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">name</span><span class="pun">},</span><span class="pln"> you are </span><span class="pun">{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">age</span><span class="pun">}</span><span class="pln"> years old
      </span><span class="pun">&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> name </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Peter'</span><span class="pln">  </span><span class="kwd">const</span><span class="pln"> age </span><span class="pun">=</span><span class="pln"> </span><span class="lit">10</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Greetings</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Hello</span><span class="pln"> name</span><span class="pun">=</span><span class="str">"Maya"</span><span class="pln"> age</span><span class="pun">={</span><span class="lit">26</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">10</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Hello</span><span class="pln"> name</span><span class="pun">={</span><span class="pln">name</span><span class="pun">}</span><span class="pln"> age</span><span class="pun">={</span><span class="pln">age</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أرسل المكوِّن App الخاصيتين على شكل قيم عائدة لمتغيّرات، كما أرسلهما أيضًا كنتيجة لتنفيذ عبارتي JavaScript، أحداهما عبارة جمع والأخرى قيمة نصية.
</p>

<h2>
	بعض الملاحظات
</h2>

<p>
	هُيّئت React لتولّد رسائل خطأ واضحةً تمامًا، وبالرغم من ذلك عليك التقدم بخطوات صغيرة، وأن تتأكد أنّ كل تغيير قد أجريته حقق الغاية منه، اتبع هذا الأسلوب في البداية على الأقل.
</p>

<p>
	ابق طرفية التطوير مفتوحةً دومًا. ولا ننصحك بمتابعة العمل إن أبلغك المتصفح بوجود أخطاء، بل عليك أن تتفهم سبب الخطأ قبل كل شيئ، وتذكر أنه يمكنك التراجع دائمًا إلى حالة العمل السابقة.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="53788" href="https://academy.hsoub.com/uploads/monthly_2020_11/browser_fail_to_compile_002.png.aff14a3965171be6e87a0bde929c9806.png" rel=""><img alt="browser_fail_to_compile_002.png" class="ipsImage ipsImage_thumbnailed" data-fileid="53788" data-unique="6wt4byu8l" src="https://academy.hsoub.com/uploads/monthly_2020_11/browser_fail_to_compile_002.png.aff14a3965171be6e87a0bde929c9806.png"></a>
</p>

<p>
	سينفعك أن تكتب التعليمة <code>()console.log</code> بين الحين والأخر ضمن أسطر شيفرة تطبيقك، حيث تطبع هذه التعليمة سجلات تنفيذ الشيفرة على الطرفية. وتذكر أنّ <strong>أسماء مكوِّنات React تبدأ بأحرف كبيرة (Capitals)</strong>، فلو حاولت تعريف مكوِّن بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8215_44" style="">
<span class="kwd">const</span><span class="pln"> footer </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      greeting app created by </span><span class="pun">&lt;</span><span class="pln">a href</span><span class="pun">=</span><span class="str">"https://github.com/mluukkai"</span><span class="pun">&gt;</span><span class="pln">mluukkai</span><span class="pun">&lt;/</span><span class="pln">a</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ثم استخدمته كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8215_46" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Greetings</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Hello</span><span class="pln"> name</span><span class="pun">=</span><span class="str">"Maya"</span><span class="pln"> age</span><span class="pun">={</span><span class="lit">26</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">10</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">footer </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لن تعرض الصفحة حينها المحتوى الذي يقدمه المكوِّن Footer، بل ستنشئ عنصرًا فارغًا يحمل اسم footer. لكن إن حولت الحرف الأول من اسم المكوِّن إلى F، ستنشئ React عنصر <code>div</code> المعرّف ضمن المكوّن Footer وسيصيّره على الصفحة.
</p>

<p>
	تذكر أن مكوِّنات React تتطلب عادة وجود عنصر جذري (root element) وحيد، فلو حاولنا تعريف المكوِّن App على سبيل المثال دون وجود العنصر <code>div</code> في البداية كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8215_48" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Greetings</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">Hello</span><span class="pln"> name</span><span class="pun">=</span><span class="str">"Maya"</span><span class="pln"> age</span><span class="pun">={</span><span class="lit">26</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">10</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">Footer</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ستكون النتيجة رسالة الخطأ التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="53790" href="https://academy.hsoub.com/uploads/monthly_2020_11/error_missing_root_element_003.png.dc1efaf9f719acd968511168612086d5.png" rel=""><img alt="error_missing_root_element_003.png" class="ipsImage ipsImage_thumbnailed" data-fileid="53790" data-unique="gap6axant" src="https://academy.hsoub.com/uploads/monthly_2020_11/error_missing_root_element_003.png.dc1efaf9f719acd968511168612086d5.png"></a>
</p>

<p>
	يمكن أن نستخدم وسيلة بديلة عن العنصر الجذري تتمثل بإنشاء مصفوفة من المكوِّنات كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8215_50" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Greetings</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;,</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">Hello</span><span class="pln"> name</span><span class="pun">=</span><span class="str">"Maya"</span><span class="pln"> age</span><span class="pun">={</span><span class="lit">26</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">10</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;,</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">Footer</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
  </span><span class="pun">]</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لا يعتبر -على الرغم من ذلك- تعريف العنصر الجذري ضمن المكوِّن الجذري لتطبيق ما أمرًا مفضلًا، بل ستظهر الشيفرة بمظهر سيئٍ قليلًا. ذلك أنّ العنصر الجذري المحدد مسبقًا، سيسبب زيادة في عدد عناصر<code>div</code> في شجرة DOM. يمكن تلافي هذا الأمر باستخدام <a href="https://wiki.hsoub.com/React/fragments#.D8.B5.D9.8A.D8.A7.D8.BA.D8.A9_.D9.85.D8.AE.D8.AA.D8.B5.D8.B1.D8.A9" rel="external">الأجزاء</a> (fragments)، أي بتغليف العناصر ليعيدها المكوِّن على شكل عناصر فارغة كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8215_52" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> name </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Peter'</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> age </span><span class="pun">=</span><span class="pln"> </span><span class="lit">10</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Greetings</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Hello</span><span class="pln"> name</span><span class="pun">=</span><span class="str">"Maya"</span><span class="pln"> age</span><span class="pun">={</span><span class="lit">26</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">10</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Hello</span><span class="pln"> name</span><span class="pun">={</span><span class="pln">name</span><span class="pun">}</span><span class="pln"> age</span><span class="pun">={</span><span class="pln">age</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Footer</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;/&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيُترجم الآن التطبيق بنجاح، ولن تحتوي شيفرة DOM على عناصر <code>div</code> زائدة.
</p>

<h2>
	التمارين 1.1 - 1.2
</h2>

<p>
	تسلّم التمارين عبر GitHub، وتحدَّد التمارين التي نفذت من خلال تطبيق <a href="https://studies.cs.helsinki.fi/stats/courses/fullstackopen" rel="external nofollow">تسليم الملفات</a> submission application. يمكنك وضع كل تمارين المنهاج التي سلمتها في نفس المكان على المنصة أو في عدة أماكن، لكن عليك أن تستخدم تسميات منطقية للمجلدات إن كنت ستضع تمارين كل الأقسام في نفس المكان. يمكنك اتباع المخطط التالي لتنظيم المجلدات والتمارين المسلمة:
</p>

<pre class="ipsCode">
part0
part1
  courseinfo
  unicafe
  anecdotes
part2
  phonebook
  countries
</pre>

<p>
	ألق نظرة على <a href="https://github.com/fullstack-hy2020/example-submission-repository" rel="external nofollow">طريقة تنظيم الملفات</a>. فلكل قسم مجلد خاص به يتفرع إلى مجلدات أخرى تضم تمارين مثل "unicafe" الموجود في القسم 1. يفضل تسليم سلسلة التمارين التي تشكل تطبيقًا معًا، ماعدا المجلد node_modules. يتوجب تسليم تمارين كل قسم على حدى، إذ لا يمكنك تسليم أية تمارين جديدة تعود إلى قسم ما إذا كنت قد سلمت غيرها من ذات القسم.
</p>

<p>
	<strong>انتبه</strong> يضم هذا القسم تمارين أخرى غير التمارين التي سنستعرضها الآن، لا تسلم التمارين التي ستنجزها في هذا الفصل بل انتظر حتى تنهي جميع تمارين القسم.
</p>

<h3>
	1.1- معلومات عن المنهاج course information، الخطوة 1
</h3>

<p>
	سنطور التطبيق الذي ننفذه انطلاقًا من هذا التمرين خلال التمارين القليلة القادمة. يكفي أن تسلم التطبيق في حالته النهائية دون تسليمه تمرينًا تمرينًا، وينطبق هذا الكلام على مجموعات التمارين المشابهة التي ستواجهها لاحقًا. بالطبع يمكنك ترك ملاحظة تشير إلى ذلك ضمن كل تمرين من السلسلة، لكنه أمر اختياري بحت.
</p>

<p>
	استخدم create-react-app لإنشاء تطبيق جديد وعدل الملف index.js ليظهر كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8215_54" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">'react'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">ReactDOM</span><span class="pln"> from </span><span class="str">'react-dom'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> course </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Half Stack application development'</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> part1 </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Fundamentals of React'</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> exercises1 </span><span class="pun">=</span><span class="pln"> </span><span class="lit">10</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> part2 </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Using props to pass data'</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> exercises2 </span><span class="pun">=</span><span class="pln"> </span><span class="lit">7</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> part3 </span><span class="pun">=</span><span class="pln"> </span><span class="str">'State of a component'</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> exercises3 </span><span class="pun">=</span><span class="pln"> </span><span class="lit">14</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;{</span><span class="pln">course</span><span class="pun">}&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">part1</span><span class="pun">}</span><span class="pln"> </span><span class="pun">{</span><span class="pln">exercises1</span><span class="pun">}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">part2</span><span class="pun">}</span><span class="pln"> </span><span class="pun">{</span><span class="pln">exercises2</span><span class="pun">}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">part3</span><span class="pun">}</span><span class="pln"> </span><span class="pun">{</span><span class="pln">exercises3</span><span class="pun">}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="typ">Number</span><span class="pln"> of exercises </span><span class="pun">{</span><span class="pln">exercises1 </span><span class="pun">+</span><span class="pln"> exercises2 </span><span class="pun">+</span><span class="pln"> exercises3</span><span class="pun">}&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="typ">ReactDOM</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(&lt;</span><span class="typ">App</span><span class="pln"> </span><span class="pun">/&gt;,</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'root'</span><span class="pun">))</span></pre>

<p>
	احذف الملفات الزائدة وهي: App.js وApp.css وApp.test.js وlogo.svg وsetupTests.js وserviceWorker.js.
</p>

<p>
	لسوء الحظ فالتطبيق ككل محتوًى في نفس المكوِّن، أعد صياغة التطبيق ليضم ثلاثة مكوِّنات جديدة: Header وContent وTotal. عدل الشيفرة التي تمرر البيانات في التطبيق App عبر الخصائص واجعل المكوِّن Header يتولى أمر البيانات المتعلقة باسم المنهاج، واجعل المكوِّن Content مسؤولًا عن تصيير البيانات المتعلقة بالأقسام وعدد التمارين في كل منها، وأخيرًا اجعل المكوِّن Total مسؤولًا عن تصيير البيانات المتعلقة بالعدد الكلي للتمارين. سيظهر جسم التطبيق الجديد تقريبًا كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8215_56" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// const-definitions</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Header</span><span class="pln"> course</span><span class="pun">={</span><span class="pln">course</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Content</span><span class="pln"> </span><span class="pun">...</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Total</span><span class="pln"> </span><span class="pun">...</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	<strong>تحذير</strong> تنشئ الأداة create-react-app مستودع git محلي يحتوي المشروع ، إلا إن كان في المجلد مستودع محلي سابق. من المرجح أنك لا تريد أن يغدو المشروع مستودعًا، لهذا نفذ الأمر التالي <code>rm -rf .git</code> في مسار المشروع.
</p>

<h3>
	1.2- معلومات عن المنهاج، الخطوة 2
</h3>

<p>
	أعد صياغة المكوِّن Content بحيث لا يصيّر بنفسه أسماء الأقسام أو عدد التمارين التي تضمها، بل يصير ثلاثة مكوِّنات تدعى Part، ثم يُصيّر كل مكوّن منها اسم قسم واحد وعدد التمارين التي يضمها.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8215_58" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Content</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">...</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Part</span><span class="pln"> </span><span class="pun">.../&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Part</span><span class="pln"> </span><span class="pun">.../&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Part</span><span class="pln"> </span><span class="pun">.../&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يمرر تطبيقنا حاليًا المعلومات بطريقة بدائية لاعتماده على متغيرات مفردة. سيتحسن الأمر قريبًا.
</p>

<p>
	<a href="https://github.com/fullstack-hy2020/fullstack-hy2020.github.io/edit/source/src/content/1/en/part1a.md" rel="external nofollow">اقترح تعديلًا على مضمون الفصل الأصلي</a>.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://fullstackopen.com/en/part1/introduction_to_react" rel="external nofollow">Introduction to React</a> من سلسلة <a href="https://fullstackopen.com/en/" rel="external nofollow">Deep Dive Into Modern Web Development</a>
</p>
]]></description><guid isPermaLink="false">1072</guid><pubDate>Fri, 13 Nov 2020 13:00:00 +0000</pubDate></item></channel></rss>
