الفرق بين المراجعتين ل"React/hooks state"

من موسوعة حسوب
اذهب إلى التنقل اذهب إلى البحث
(إنشاء الصفحة)
 
(اكمال إضافة الصفحة)
سطر 1: سطر 1:
 +
<noinclude>{{DISPLAYTITLE:خطاف الحالة في React}}</noinclude>
 
''الخطافات هي إضافة جديدة إلى الإصدار 16.8 في React، إذ تسمح لك باستعمال ميزة الحالة وميزات React الأخرى دون كتابة أي صنف.''
 
''الخطافات هي إضافة جديدة إلى الإصدار 16.8 في React، إذ تسمح لك باستعمال ميزة الحالة وميزات React الأخرى دون كتابة أي صنف.''
  
سطر 20: سطر 21:
  
 
== مثال عن صنف مكافئ لخطاف ==
 
== مثال عن صنف مكافئ لخطاف ==
إن استعملت الأصناف في React من قبل، فيجب أن تكون الشيفرة التالية مألوفة لديك:<syntaxhighlight lang="javascript">
+
إن استعملت الأصناف في [[React]] من قبل، فيجب أن تكون الشيفرة التالية مألوفة لديك:<syntaxhighlight lang="javascript">
 
class Example extends React.Component {
 
class Example extends React.Component {
 
   constructor(props) {
 
   constructor(props) {
سطر 40: سطر 41:
 
   }
 
   }
 
}
 
}
</syntaxhighlight>الحالة الأولية تكون { count: 0 }، ونعمل على زيادة state.count عندما يضغط المستخدم على زر يستدعي this.setState(). سنستعمل أجزاء من هذا الصنف في أقسام لاحقة من هذه الصفحة.
+
</syntaxhighlight>الحالة الأولية تكون <code>{ count: 0 }</code>، ونعمل على زيادة <code>state.count</code> عندما يضغط المستخدم على زر يستدعي <code>this.setState()‎</code>. سنستعمل أجزاء من هذا الصنف في أقسام لاحقة من هذه الصفحة.
  
 
'''ملاحظة''': قد تتساءل عن سبب استعمالنا عدادًا هنا عوضَ استعمال مثال أكثر واقعية. يكمن السبب في أن هذا المثال يساعدنا على التركيز على الواجهة البرمجية في بداية رحلتنا مع الخطافات.
 
'''ملاحظة''': قد تتساءل عن سبب استعمالنا عدادًا هنا عوضَ استعمال مثال أكثر واقعية. يكمن السبب في أن هذا المثال يساعدنا على التركيز على الواجهة البرمجية في بداية رحلتنا مع الخطافات.
  
 
== الخطافات ومكونات دالة ==
 
== الخطافات ومكونات دالة ==
لنتذكر سويةً، تبدو مكونات دالة في React بالشكل:<syntaxhighlight lang="javascript">
+
لنتذكر سويةً، تبدو مكونات دالة في [[React]] بالشكل:<syntaxhighlight lang="javascript">
 
const Example = (props) => {
 
const Example = (props) => {
 
   // تستطيع استعمال الخطافات هنا
 
   // تستطيع استعمال الخطافات هنا
سطر 55: سطر 56:
 
   return <div />;
 
   return <div />;
 
}
 
}
</syntaxhighlight>ربما كنت تعرف مسبقًا أن هذه المكونات هي "مكونات عديمة الحالة" (stateless components). نحن الآن نعرِّف إمكانية استعمال حالة React من هذه المكونات، لذا نفضل الاسم "مكونات دالة".
+
</syntaxhighlight>ربما كنت تعرف مسبقًا أن هذه المكونات هي "مكونات عديمة الحالة" (stateless components). نحن الآن نعرِّف إمكانية استعمال حالة [[React]] من هذه المكونات، لذا نفضل الاسم "مكونات دالة".
  
 
لا تعمل الخطافات داخل الأصناف، ولكن يمكن استعمالها بدلًا من كتابة أصناف.
 
لا تعمل الخطافات داخل الأصناف، ولكن يمكن استعمالها بدلًا من كتابة أصناف.
  
 
== ما هو الخطاف؟ ==
 
== ما هو الخطاف؟ ==
يبدأ مثالنا الجديد باستيراد الخطاف useState من React:<syntaxhighlight lang="javascript">
+
يبدأ مثالنا الجديد باستيراد الخطاف <code>useState</code> من [[React]]:<syntaxhighlight lang="javascript">
 
import React, { useState } from 'react';
 
import React, { useState } from 'react';
  
سطر 66: سطر 67:
 
   // ...
 
   // ...
 
}
 
}
</syntaxhighlight>إذًا، ما هو الخطاف تحديدًا؟ الخطاف هو دالة مميزة تمكنك من "تعليق أو ربط" (hook into) ميزات React مع بعضها. على سبيل المثال، useState هو خطاف يمكنك من إضافة حالة React إلى مكونات دالة. سنتطرق إلى الخطافات الأخرى لاحقًا.
+
</syntaxhighlight>إذًا، ما هو الخطاف تحديدًا؟ الخطاف هو دالة مميزة تمكنك من "تعليق أو ربط" (hook into) ميزات [[React]] مع بعضها. على سبيل المثال، <code>useState</code> هو خطاف يمكنك من إضافة حالة [[React]] إلى مكونات دالة. سنتطرق إلى الخطافات الأخرى لاحقًا.
  
متى يمكنني استعمال الخطاف؟ إن كتبت مكون دالة ووجدت أنك بحاجة إلى إضافة بعض الحالة له، فستحتاج - سابقًا قبل عصر الخطافات - إلى تحويله إلى صنف. الآن، يمكنك استعمال خطاف داخل مكون دالة موجودة وهو ما سنفعله الآن.
+
'''متى يمكنني استعمال الخطاف؟'''
  
ملاحظة: هنالك بعض القواعد المخصصة تحدد المكان المسموح والمحظور فيه استعمال الخطافات ضمن مكون. سنشرح هذه القواعد بالتفصيل الممل في توثيق [[React/hooks rules|قواعد استعمال الخطافات]].
+
إن كتبت مكون دالة ووجدت أنك بحاجة إلى إضافة بعض الحالة له، فستحتاج - سابقًا قبل عصر الخطافات - إلى تحويله إلى صنف. الآن، يمكنك استعمال خطاف داخل مكون دالة موجودة وهو ما سنفعله الآن.
 +
 
 +
'''ملاحظة''': هنالك بعض القواعد المخصصة تحدد المكان المسموح والمحظور فيه استعمال الخطافات ضمن مكون. سنشرح هذه القواعد بالتفصيل الممل في توثيق [[React/hooks rules|قواعد استعمال الخطافات]].
  
 
== التصريح عن متغير حالة ==
 
== التصريح عن متغير حالة ==
إن كنا سنستعمل صنفًا، نهيِّئ فيه الحالة count إلى 0 عبر ضبط this.state إلى { count: 0 } في باني هذا الصنف:<syntaxhighlight lang="javascript">
+
إن كنا سنستعمل صنفًا، نهيِّئ فيه الحالة <code>count</code> إلى 0 عبر ضبط <code>this.state</code> إلى <code>{ count: 0 }</code> في باني هذا الصنف:<syntaxhighlight lang="javascript">
 
class Example extends React.Component {
 
class Example extends React.Component {
 
   constructor(props) {
 
   constructor(props) {
سطر 81: سطر 84:
 
     };
 
     };
 
   }
 
   }
</syntaxhighlight>في مكون دالة، لا يمكننا استعمال this، لذا لا نستطيع إسناد إو قراء this.state. عوض ذلك، يمكننا استدعاء الخطاف useState مباشرةً داخل المكون الخاص بنا:<syntaxhighlight lang="javascript">
+
</syntaxhighlight>في مكون دالة، لا يمكننا استعمال <code>this</code>، لذا لا نستطيع إسناد إو قراء <code>this.state</code>. عوض ذلك، يمكننا استدعاء الخطاف <code>useState</code> مباشرةً داخل المكون الخاص بنا:<syntaxhighlight lang="javascript">
 
import React, { useState } from 'react';
 
import React, { useState } from 'react';
  
سطر 87: سطر 90:
 
   // "count" التصريح عن متغير حالة جديد ندعوه
 
   // "count" التصريح عن متغير حالة جديد ندعوه
 
   const [count, setCount] = useState(0);
 
   const [count, setCount] = useState(0);
</syntaxhighlight>ماذا يفعل استدعاء useState؟ إنَّه يصرِّح عن "متغير حالة" (state variable). هذا المتغير يدعى count ولكن يمكننا أن ندعوه بأي اسم آخر مثل banana. هذه هي طريقة لحفظ بعض القيم بين استدعاءات الدالة، إذ useState هي طريقة جديدة لاستعمال الامكانيات نفسها التي توفرها this.state في الصنف. عمومًا، المتغيرات "تختفي" عند اكتمال تنفيذ الدالة وخروجها ولكن متغيرات الحالة تحافظ على قيمتها في React.
+
</syntaxhighlight>'''ماذا يفعل استدعاء <code>useState</code>؟'''
  
لماذا نمرر وسيطًا إلى useState؟
+
إنَّه يصرِّح عن "متغير حالة" (state variable). هذا المتغير يدعى <code>count</code> ولكن يمكننا أن ندعوه بأي اسم آخر مثل <code>banana</code>. هذه هي طريقة لحفظ بعض القيم بين استدعاءات الدالة، إذ <code>useState</code> هي طريقة جديدة لاستعمال الامكانيات نفسها التي توفرها <code>this.state</code> في الصنف. عمومًا، المتغيرات "تختفي" عند اكتمال تنفيذ الدالة وخروجها ولكن متغيرات الحالة تحافظ على قيمتها في [[React]].
  
الوسيط الوحيد الذي يمكن تمريره إلى الخطاف useState() هو الحالة الأولية. خلافًا للأصناف، ليس من الضروري أن تكون الحالة كائنًا. يمكننا استعمال عدد أو سلسلة نصية إن كان ذلك ما نحتاجه. في مثالنا، نحتاج إلى عدد ليمثل عدد المرات التي ضغط فيها المستخدم على الزر، لذا مرَّرنا العدد 0 ليكون الحالة الأولية لمتغيرنا. (إن أردنا تخزين قيمتين مختلفتين في حالة، فيمكننا فعل ذلك عبر استدعاء useState() مرتين.)
+
'''لماذا نمرر وسيطًا إلى useState؟'''
  
ما الذي يعيده useState؟
+
الوسيط الوحيد الذي يمكن تمريره إلى الخطاف <code>useState()‎</code> هو الحالة الأولية. خلافًا للأصناف، ليس من الضروري أن تكون الحالة كائنًا. يمكننا استعمال عدد أو سلسلة نصية إن كان ذلك ما نحتاجه. في مثالنا، نحتاج إلى عدد ليمثل عدد المرات التي ضغط فيها المستخدم على الزر، لذا مرَّرنا العدد 0 ليكون الحالة الأولية لمتغيرنا. (إن أردنا تخزين قيمتين مختلفتين في حالة، فيمكننا فعل ذلك عبر استدعاء <code>useState()‎</code> مرتين.)
  
إنه يعيد زوجًا من القيم: الحالة الحالية، ودالة تحدِّثها. لهذا السبب، نكتب const [count, setCount] = useState(). هذا الأمر يشبه this.state.count و this.setState في الصنف، باستثناء أننا نحصل عليهم كزوج من القيم. إن لم تكن الصيغة السابقة التي استعملناها مألوفة لك، فسنتطرق إليها في آخر هذه الصفحة.
+
'''ما الذي يعيده <code>useState</code>؟'''
  
الآن وقد عرفنا ما الذي يفعله الخطاف useState، يجب أن تكون الشيفرة التالية مفهومة تمامًا لك:<syntaxhighlight lang="javascript">
+
إنه يعيد زوجًا من القيم: الحالة الحالية، ودالة تحدِّثها. لهذا السبب، نكتب <code>const [count, setCount] = useState()‎</code>. هذا الأمر يشبه <code>this.state.count</code> و <code>this.setState</code> في الصنف، باستثناء أننا نحصل عليهم كزوج من القيم. إن لم تكن الصيغة السابقة التي استعملناها مألوفة لك، فسنتطرق إليها في آخر هذه الصفحة.
 +
 
 +
الآن وقد عرفنا ما الذي يفعله الخطاف <code>useState</code>، يجب أن تكون الشيفرة التالية مفهومة تمامًا لك:<syntaxhighlight lang="javascript">
 
import React, { useState } from 'react';
 
import React, { useState } from 'react';
  
سطر 103: سطر 108:
 
   // "count" التصريح عن متغير حالة جديد ندعوه
 
   // "count" التصريح عن متغير حالة جديد ندعوه
 
   const [count, setCount] = useState(0);
 
   const [count, setCount] = useState(0);
</syntaxhighlight>صرَّحنا عن متغير حالة يدعى count، وأسندنا القيمة 0 العددية له. ستتذكر React قيمته الاحلية بين عمليات إعادة التصيير، وتوفر الحالة الأحدث له للدالة. إ نأردنا تحديث قيمة المتغير count الحالية، يمكننا استدعاء useState.
+
</syntaxhighlight>صرَّحنا عن متغير حالة يدعى <code>count</code>، وأسندنا القيمة 0 العددية له. ستتذكر [[React]] قيمته الاحلية بين عمليات إعادة التصيير، وتوفر الحالة الأحدث له للدالة. إ نأردنا تحديث قيمة المتغير <code>count</code> الحالية، يمكننا استدعاء <code>useState</code>.
  
ملاحظة: قد تتسائل عن سبب استعمال الاسم useState لهذا الخطاف وليس الاسم createState؟ الجواب هو أن "إنشاء" (create) لن تكون دقيقة والسبب أن الحالة تُنشَأ عندما يصير المكون أول مرة. في عمليات التصيير اللاحقة، يعطينا الخطاف useState القيمة (الحالة) الحالية وإلا لما كنا أطلقنا عليها "حالة" (state) على الإطلاق. هنالك أيضًا سبب متعلق ببدء تسمية الخطافات بالكلمة use، وسنتعرف عليه في توثيق "[[React/hooks rules|قواعد استعمال الخطافات]]".
+
'''ملاحظة''': قد تتسائل عن سبب استعمال الاسم <code>useState</code> لهذا الخطاف وليس الاسم <code>createState</code>؟ الجواب هو أن "إنشاء" (create) لن تكون دقيقة والسبب أنَّ الحالة تُنشَأ عندما يصيَّر المكون أول مرة. في عمليات التصيير اللاحقة، يعطينا الخطاف <code>useState</code> القيمة (الحالة) الحالية وإلا لما كنا أطلقنا عليها "حالة" (state) على الإطلاق. هنالك أيضًا سبب متعلق ببدء تسمية الخطافات بالكلمة <code>use</code>، وسنتعرف عليه في توثيق "[[React/hooks rules|قواعد استعمال الخطافات]]".
  
 
== قراءة الحالة ==
 
== قراءة الحالة ==
إن أردنا إظهار قيمة المتغير count الحالية في صنف، يمكنن أن نقرأ this.state.count:<syntaxhighlight lang="html">
+
إن أردنا إظهار قيمة المتغير <code>count</code> الحالية في صنف، يمكنن أن نقرأ <code>this.state.count</code>:<syntaxhighlight lang="html">
 
<p>You clicked {this.state.count} times</p>
 
<p>You clicked {this.state.count} times</p>
</syntaxhighlight>في دال، يمكننا استعمال المتغير count مباشرةً:<syntaxhighlight lang="html">
+
</syntaxhighlight>في دال، يمكننا استعمال المتغير <code>count</code> مباشرةً:<syntaxhighlight lang="html">
 
<p>You clicked {count} times</p>
 
<p>You clicked {count} times</p>
  
سطر 116: سطر 121:
  
 
== تحديث الحالة ==
 
== تحديث الحالة ==
في الصنف، نحتاج إلى استدعاء this.setState() لتحديث الحالة count:<syntaxhighlight lang="html">
+
في الصنف، نحتاج إلى استدعاء <code>this.setState()‎</code> لتحديث الحالة <code>count</code>:<syntaxhighlight lang="html">
 
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
 
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
 
   Click me
 
   Click me
 
</button>
 
</button>
</syntaxhighlight>في الدالة، لدينا setState و count مسبقًا كمتغيرات، لذا لا تحتاج إلى this:<syntaxhighlight lang="html">
+
</syntaxhighlight>في الدالة، لدينا <code>setState</code> و <code>count</code> مسبقًا كمتغيرات، لذا لا تحتاج إلى <code>this</code>:<syntaxhighlight lang="html">
 
<button onClick={() => setCount(count + 1)}>
 
<button onClick={() => setCount(count + 1)}>
 
   Click me
 
   Click me
سطر 143: سطر 148:
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
* '''السطر 1''': استوردنا الخطاف useState من React. هذا يمكننا من إبقاء حالة محلية (local state) في مكون دالة.
+
* '''السطر 1''': استوردنا الخطاف <code>useState</code> من [[React]]. هذا يمكننا من إبقاء حالة محلية (local state) في مكون دالة.
  
* '''السطر 4''': داخل المكون Example، صرَّحنا عن متغير حالة جديد عبر استدعاء الخطاف useState. يعيد الخطاف زوجًا من القيم أعطينا لكل من هاتين القيمتين اسمًا. سنتحاج إلى استدعاء المتغير count لأنه يحمل عدد ضغطات الزر. هيَّأنا هذا المتغير إلى القيمة 0 عبر تمرير هذه القيمة إلى useState. القيمة الثانية من الزوج الذي يعيده الخطاف هي دالة بحد ذاتها. هذه الدالة تحدِّث المتغير count، لذا سنطلق عليها setCount.
+
* '''السطر 4''': داخل المكون <code>Example</code>، صرَّحنا عن متغير حالة جديد عبر استدعاء الخطاف <code>useState</code>. يعيد الخطاف زوجًا من القيم أعطينا لكل من هاتين القيمتين اسمًا. سنتحاج إلى استدعاء المتغير <code>count</code> لأنه يحمل عدد ضغطات الزر. هيَّأنا هذا المتغير إلى القيمة 0 عبر تمرير هذه القيمة إلى <code>useState</code>. القيمة الثانية من الزوج الذي يعيده الخطاف هي دالة بحد ذاتها. هذه الدالة تحدِّث المتغير <code>count</code>، لذا سنطلق عليها <code>setCount</code>.
  
* '''السطر 9''': عندما يضغط المستخدم على الزر، تُستدعَى الدالة setCount مع القيمة الجديدة. ستعيد React بعد ذلك تصيير المكون Example مع تمرير القيمة count الجديدة إليه.
+
* '''السطر 9''': عندما يضغط المستخدم على الزر، تُستدعَى الدالة <code>setCount</code> مع القيمة الجديدة. ستعيد [[React]] بعد ذلك تصيير المكون <code>Example</code> مع تمرير القيمة <code>count</code> الجديدة إليه.
قد تبدو للوهلة الأولى أن هذا كثير ويحتاج إلى فهم وتركيز كبيرة. لا تتسرع بالحكم. إن شعرت أنك قد فقدت تركيزك أثناء الشرح، أعد قراءة الشيفرات بدءًا من بداية الدرس مجددًا وحاول فهم كل سطر منها. نعدك إن نسيت (مؤقتًا) كيفية عمل الحالة في الأصناف ونظرت إلى الشيفرة مجدَّدًا، فستفهمها بشكل كامل.
+
قد يبدو للوهلة الأولى أن هذا كثير ويحتاج إلى فهم وتركيز كبيرة. لا تتسرع بالحكم. إن شعرت أنك قد فقدت تركيزك أثناء الشرح، أعد قراءة الشيفرات بدءًا من بداية الدرس مجددًا وحاول فهم كل سطر منها. نعدك إن نسيت (مؤقتًا) كيفية عمل الحالة في الأصناف ونظرت إلى الشيفرة مجدَّدًا، فستفهمها بشكل كامل.
  
== إضافة: ما الذي تعنيه الأقواس المعقوفة؟ ==
+
=== إضافة: ما الذي تعنيه الأقواس المعقوفة؟ ===
 
لابد أنك لاحظ وجود أقواس معقوفة عند التصريح عن متغير حالة:<syntaxhighlight lang="javascript">
 
لابد أنك لاحظ وجود أقواس معقوفة عند التصريح عن متغير حالة:<syntaxhighlight lang="javascript">
 
const [count, setCount] = useState(0);
 
const [count, setCount] = useState(0);
  
</syntaxhighlight>الأسماء في القسم الأيسر ليست جزءًا من واجهة React البرمجية. يمكنك أن تسمي متغيرات الحالة الخاصة بك بأي اسم تريد:<syntaxhighlight lang="javascript">
+
</syntaxhighlight>الأسماء في القسم الأيسر ليست جزءًا من واجهة [[React]] البرمجية. يمكنك أن تسمي متغيرات الحالة الخاصة بك بأي اسم تريد:<syntaxhighlight lang="javascript">
 
const [fruit, setFruit] = useState('banana');
 
const [fruit, setFruit] = useState('banana');
</syntaxhighlight>هذه الصيغة هي إحدى صيغ جافاسكربت يطلق عليها "[[JavaScript/Destructuring Assignment|تفكيك المصفوفات]]". إنها تعني أننا نريد إنشاء متغيِّرين جديدين هما: fruit و setFruit، إذ الأول يعيَّن إلى أول قيمة يعيدها useState، والثاني يعين إلى القيمة الثانية المعادة. هذا يكافئ الشيفرة التالية:<syntaxhighlight lang="javascript">
+
</syntaxhighlight>هذه الصيغة هي إحدى صيغ جافاسكربت يطلق عليها "[[JavaScript/Destructuring Assignment|تفكيك المصفوفات]]". إنها تعني أننا نريد إنشاء متغيِّرين جديدين هما: <code>fruit</code> و <code>setFruit</code>، إذ الأول يعيَّن إلى أول قيمة يعيدها <code>useState</code>، والثاني يعين إلى القيمة الثانية المعادة. هذا يكافئ الشيفرة التالية:<syntaxhighlight lang="javascript">
var fruitStateVariable = useState('banana'); // Returns a pair
+
var fruitStateVariable = useState('banana'); // يعيد زوجًا
var fruit = fruitStateVariable[0]; // First item in a pair
+
var fruit = fruitStateVariable[0]; // أول عنصر من الزوج
var setFruit = fruitStateVariable[1]; // Second item in a pair
+
var setFruit = fruitStateVariable[1]; // ثاني عنصر من الزوج
</syntaxhighlight>عندما صرحنا عن متغير حالة مع useState، فإن هذا الخطاف يعيد زوجًا من القيم في مصفوفة بعنصرين. العنصر الأولي هو القيمة الحالية، والعنصر الثاني هو الدالة التي
+
</syntaxhighlight>عندما صرحنا عن متغير حالة مع <code>useState</code>، فإن هذا الخطاف يعيد زوجًا من القيم في مصفوفة بعنصرين. العنصر الأولي هو القيمة الحالية، والعنصر الثاني هو الدالة التي تمكننا من تحديثها. استعمال <code>[0]</code> و <code>[1]</code> للوصول إلى هاتين القيمتين أمرٌ مربك لأن لهما معنى محدَّد. هذا هو سبب استعمالنا أسلوك [[JavaScript/Destructuring Assignment|الإسناد بالتفكيك]] عوضًا عن ذلك.
 +
 
 +
'''ملاحظة''': ربما انتابك شيءٌ من الفضول حول كيفية معرفة [[React]] أي مكون يقابل <code>useState</code> لمَّا كنا نعيد تمرير أي شي مثل <code>this</code> إلى [[React]].لا تقلق، سنجيب عن هذا السؤال وأسئلة أخرى في صفحة [[React/hooks faq|الأسئلة الشائعة حول الخطافات]].
 +
 
 +
=== إضافة: استعمال متغيرات حالة عديدة ===
 +
التصريح عن متغيرات حالة كأزواج من <code>[something, setSomething]</code> هو أمر عملي وجيد، إذ يسمح لنا بإعطاء أسماء مختلفة لمتغيرات مختلفة للحالة إن أردنا استعمال أكثر من متغير حالة واحد:<syntaxhighlight lang="javascript">
 +
function ExampleWithManyStates() {
 +
  // التصريح عن متغيرات حالة عديدة
 +
  const [age, setAge] = useState(42);
 +
  const [fruit, setFruit] = useState('banana');
 +
  const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
 +
</syntaxhighlight>في هذا المكون في الشيفرة الآنفة، لدينا المتغيرات <code>age</code>، و <code>fruit</code>، و <code>todos</code> بوصفها متغيرات حالة، ويمكننا تحديث كل منها على حدة:<syntaxhighlight lang="javascript">
 +
function handleOrangeClick() {
 +
    // this.setState({ fruit: 'orange' }) يشبه
 +
    setFruit('orange');
 +
  }
 +
</syntaxhighlight>لا يتوجب عليه استعمال عدة متغيرات حالة. متغيرات الحالة يمكنها أن تحوي كائنات ومصفوفات، لذا لا يزال بإمكانك تجميع البيانات المترابطة مع بعضها بعضًا. على أي حال، تحديث متغير حالة يستبدل دومًا قيمته بدلًا من دمجها، وهذا يخالف سلوك <code>this.setState</code> في الأصناف.
 +
 
 +
أعطينا الكثير من التوصيات حول فصل متغيرات الحالة المستقلة في صفحة [[React/hooks faq|الأسئلة الشائعة حول الخطافات]].
 +
 
 +
== الخطوات التالية ==
 +
تعلمنا حول أحد الخطافات التي توفرها [[React]] وهو الخطاف <code>useState</code>. في أغلب الأحيان، سنشير إليه بالاسم "خطاف الحالة" (State Hook). يسمح لنا هذا الخطاف بإضافة حالة محلية إلى مكونات دالة في [[React]] بخطوات بسيطة وشيفرة أقل.
 +
 
 +
تعلمنا أيضًا القليل حول ماهية الخطافات. كما رأينا، الخطافات هي دوال تمكنك من "تعليق أو ربط" (hook into) ميزات [[React]] من مكونات دالة. أسماء الخطافات تبدأ دومًا بالكلمة <code>use</code>، وهنالك الكثير من الخطافات التي لم نرها بعد.
 +
 
 +
لنكمل الآن وننتقل إلى الخطاف التالي وهو الخطاف <code>useEffect</code>. يسمح لنا هذا الخطاف بتنفيذ تأثيرات جانبية (side effects) في المكونات، وهو يشبه توابع دورة الحياة في الأصناف.
 +
 
 +
== انظر أيضًا==
 +
*[[React/hooks intro|مدخل إلى الخطافات]]
 +
*[[React/hooks overview|لمحة خاطفة عن الخطافات]]
 +
*خطاف الحالة  (الصفحة الحالية)
 +
*[[React/hooks effect|خطاف التأثير]]
 +
*[[React/hooks rules|قواعد استعمال الخطافات]]
 +
*[[React/hooks custom|بناء خطافات خاصة بك]]
 +
*[[React/hooks reference|مرجع إلى الواجهة البرمجية للخطافات]]
 +
*[[React/hooks faq|الأسئلة الشائعة حول الخطافات]]
 +
== مصادر==
 +
*[https://reactjs.org/docs/hooks-overview.html صفحة لمحة خاطفة عن الخطافات في توثيق React الرسمي.]
 +
[[تصنيف:React]]
 +
[[تصنيف:React Hooks]]

مراجعة 15:30، 12 فبراير 2019

الخطافات هي إضافة جديدة إلى الإصدار 16.8 في React، إذ تسمح لك باستعمال ميزة الحالة وميزات React الأخرى دون كتابة أي صنف.

شرحت الصفحة السابقة في قسم خطاف الحالة هذا الخطاف عبر المثال التالي:

import React, { useState } from 'react';

function Example() {
  // "count" التصريح عن متغير حالة جديد ندعوه
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

بادئ ذي بدء، سنتعرف على الخطافات عبر موازنة هذه الشيفرة مع الصنف المكافئ لها.

مثال عن صنف مكافئ لخطاف

إن استعملت الأصناف في React من قبل، فيجب أن تكون الشيفرة التالية مألوفة لديك:

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}

الحالة الأولية تكون { count: 0 }، ونعمل على زيادة state.count عندما يضغط المستخدم على زر يستدعي this.setState()‎. سنستعمل أجزاء من هذا الصنف في أقسام لاحقة من هذه الصفحة.

ملاحظة: قد تتساءل عن سبب استعمالنا عدادًا هنا عوضَ استعمال مثال أكثر واقعية. يكمن السبب في أن هذا المثال يساعدنا على التركيز على الواجهة البرمجية في بداية رحلتنا مع الخطافات.

الخطافات ومكونات دالة

لنتذكر سويةً، تبدو مكونات دالة في React بالشكل:

const Example = (props) => {
  // تستطيع استعمال الخطافات هنا
  return <div />;
}

أو الشكل التالي:

function Example(props) {
  // تستطيع استعمال الخطافات هنا
  return <div />;
}

ربما كنت تعرف مسبقًا أن هذه المكونات هي "مكونات عديمة الحالة" (stateless components). نحن الآن نعرِّف إمكانية استعمال حالة React من هذه المكونات، لذا نفضل الاسم "مكونات دالة".

لا تعمل الخطافات داخل الأصناف، ولكن يمكن استعمالها بدلًا من كتابة أصناف.

ما هو الخطاف؟

يبدأ مثالنا الجديد باستيراد الخطاف useState من React:

import React, { useState } from 'react';

function Example() {
  // ...
}

إذًا، ما هو الخطاف تحديدًا؟ الخطاف هو دالة مميزة تمكنك من "تعليق أو ربط" (hook into) ميزات React مع بعضها. على سبيل المثال، useState هو خطاف يمكنك من إضافة حالة React إلى مكونات دالة. سنتطرق إلى الخطافات الأخرى لاحقًا.

متى يمكنني استعمال الخطاف؟

إن كتبت مكون دالة ووجدت أنك بحاجة إلى إضافة بعض الحالة له، فستحتاج - سابقًا قبل عصر الخطافات - إلى تحويله إلى صنف. الآن، يمكنك استعمال خطاف داخل مكون دالة موجودة وهو ما سنفعله الآن.

ملاحظة: هنالك بعض القواعد المخصصة تحدد المكان المسموح والمحظور فيه استعمال الخطافات ضمن مكون. سنشرح هذه القواعد بالتفصيل الممل في توثيق قواعد استعمال الخطافات.

التصريح عن متغير حالة

إن كنا سنستعمل صنفًا، نهيِّئ فيه الحالة count إلى 0 عبر ضبط this.state إلى { count: 0 } في باني هذا الصنف:

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

في مكون دالة، لا يمكننا استعمال this، لذا لا نستطيع إسناد إو قراء this.state. عوض ذلك، يمكننا استدعاء الخطاف useState مباشرةً داخل المكون الخاص بنا:

import React, { useState } from 'react';

function Example() {
  // "count" التصريح عن متغير حالة جديد ندعوه
  const [count, setCount] = useState(0);

ماذا يفعل استدعاء useState؟

إنَّه يصرِّح عن "متغير حالة" (state variable). هذا المتغير يدعى count ولكن يمكننا أن ندعوه بأي اسم آخر مثل banana. هذه هي طريقة لحفظ بعض القيم بين استدعاءات الدالة، إذ useState هي طريقة جديدة لاستعمال الامكانيات نفسها التي توفرها this.state في الصنف. عمومًا، المتغيرات "تختفي" عند اكتمال تنفيذ الدالة وخروجها ولكن متغيرات الحالة تحافظ على قيمتها في React.

لماذا نمرر وسيطًا إلى useState؟

الوسيط الوحيد الذي يمكن تمريره إلى الخطاف useState()‎ هو الحالة الأولية. خلافًا للأصناف، ليس من الضروري أن تكون الحالة كائنًا. يمكننا استعمال عدد أو سلسلة نصية إن كان ذلك ما نحتاجه. في مثالنا، نحتاج إلى عدد ليمثل عدد المرات التي ضغط فيها المستخدم على الزر، لذا مرَّرنا العدد 0 ليكون الحالة الأولية لمتغيرنا. (إن أردنا تخزين قيمتين مختلفتين في حالة، فيمكننا فعل ذلك عبر استدعاء useState()‎ مرتين.)

ما الذي يعيده useState؟

إنه يعيد زوجًا من القيم: الحالة الحالية، ودالة تحدِّثها. لهذا السبب، نكتب const [count, setCount] = useState()‎. هذا الأمر يشبه this.state.count و this.setState في الصنف، باستثناء أننا نحصل عليهم كزوج من القيم. إن لم تكن الصيغة السابقة التي استعملناها مألوفة لك، فسنتطرق إليها في آخر هذه الصفحة.

الآن وقد عرفنا ما الذي يفعله الخطاف useState، يجب أن تكون الشيفرة التالية مفهومة تمامًا لك:

import React, { useState } from 'react';

function Example() {
  // "count" التصريح عن متغير حالة جديد ندعوه
  const [count, setCount] = useState(0);

صرَّحنا عن متغير حالة يدعى count، وأسندنا القيمة 0 العددية له. ستتذكر React قيمته الاحلية بين عمليات إعادة التصيير، وتوفر الحالة الأحدث له للدالة. إ نأردنا تحديث قيمة المتغير count الحالية، يمكننا استدعاء useState.

ملاحظة: قد تتسائل عن سبب استعمال الاسم useState لهذا الخطاف وليس الاسم createState؟ الجواب هو أن "إنشاء" (create) لن تكون دقيقة والسبب أنَّ الحالة تُنشَأ عندما يصيَّر المكون أول مرة. في عمليات التصيير اللاحقة، يعطينا الخطاف useState القيمة (الحالة) الحالية وإلا لما كنا أطلقنا عليها "حالة" (state) على الإطلاق. هنالك أيضًا سبب متعلق ببدء تسمية الخطافات بالكلمة use، وسنتعرف عليه في توثيق "قواعد استعمال الخطافات".

قراءة الحالة

إن أردنا إظهار قيمة المتغير count الحالية في صنف، يمكنن أن نقرأ this.state.count:

<p>You clicked {this.state.count} times</p>

في دال، يمكننا استعمال المتغير count مباشرةً:

<p>You clicked {count} times</p>

تحديث الحالة

في الصنف، نحتاج إلى استدعاء this.setState()‎ لتحديث الحالة count:

<button onClick={() => this.setState({ count: this.state.count + 1 })}>
  Click me
</button>

في الدالة، لدينا setState و count مسبقًا كمتغيرات، لذا لا تحتاج إلى this:

<button onClick={() => setCount(count + 1)}>
  Click me
</button>

الخلاصة

لنراجع ما تعلمناه بالمرور على كل سطر من أسطر الشيفرة والتأكد من فهمنا للخطافات بشكل عام ولخطاف الحالة بشكل خاص:

 1 import React, { useState } from 'react';
 2 
 3 function Example() {
 4    const [count, setCount] = useState(0);
 5 
 6   return (
 7     <div>
 8       <p>You clicked {count} times</p>
 9       <button onClick={() => setCount(count + 1)}>
10        Click me
11       </button>
12     </div>
13   );
14 }
  • السطر 1: استوردنا الخطاف useState من React. هذا يمكننا من إبقاء حالة محلية (local state) في مكون دالة.
  • السطر 4: داخل المكون Example، صرَّحنا عن متغير حالة جديد عبر استدعاء الخطاف useState. يعيد الخطاف زوجًا من القيم أعطينا لكل من هاتين القيمتين اسمًا. سنتحاج إلى استدعاء المتغير count لأنه يحمل عدد ضغطات الزر. هيَّأنا هذا المتغير إلى القيمة 0 عبر تمرير هذه القيمة إلى useState. القيمة الثانية من الزوج الذي يعيده الخطاف هي دالة بحد ذاتها. هذه الدالة تحدِّث المتغير count، لذا سنطلق عليها setCount.
  • السطر 9: عندما يضغط المستخدم على الزر، تُستدعَى الدالة setCount مع القيمة الجديدة. ستعيد React بعد ذلك تصيير المكون Example مع تمرير القيمة count الجديدة إليه.

قد يبدو للوهلة الأولى أن هذا كثير ويحتاج إلى فهم وتركيز كبيرة. لا تتسرع بالحكم. إن شعرت أنك قد فقدت تركيزك أثناء الشرح، أعد قراءة الشيفرات بدءًا من بداية الدرس مجددًا وحاول فهم كل سطر منها. نعدك إن نسيت (مؤقتًا) كيفية عمل الحالة في الأصناف ونظرت إلى الشيفرة مجدَّدًا، فستفهمها بشكل كامل.

إضافة: ما الذي تعنيه الأقواس المعقوفة؟

لابد أنك لاحظ وجود أقواس معقوفة عند التصريح عن متغير حالة:

const [count, setCount] = useState(0);

الأسماء في القسم الأيسر ليست جزءًا من واجهة React البرمجية. يمكنك أن تسمي متغيرات الحالة الخاصة بك بأي اسم تريد:

const [fruit, setFruit] = useState('banana');

هذه الصيغة هي إحدى صيغ جافاسكربت يطلق عليها "تفكيك المصفوفات". إنها تعني أننا نريد إنشاء متغيِّرين جديدين هما: fruit و setFruit، إذ الأول يعيَّن إلى أول قيمة يعيدها useState، والثاني يعين إلى القيمة الثانية المعادة. هذا يكافئ الشيفرة التالية:

var fruitStateVariable = useState('banana'); // يعيد زوجًا
var fruit = fruitStateVariable[0]; // أول عنصر من الزوج
var setFruit = fruitStateVariable[1]; // ثاني عنصر من الزوج

عندما صرحنا عن متغير حالة مع useState، فإن هذا الخطاف يعيد زوجًا من القيم في مصفوفة بعنصرين. العنصر الأولي هو القيمة الحالية، والعنصر الثاني هو الدالة التي تمكننا من تحديثها. استعمال [0] و [1] للوصول إلى هاتين القيمتين أمرٌ مربك لأن لهما معنى محدَّد. هذا هو سبب استعمالنا أسلوك الإسناد بالتفكيك عوضًا عن ذلك.

ملاحظة: ربما انتابك شيءٌ من الفضول حول كيفية معرفة React أي مكون يقابل useState لمَّا كنا نعيد تمرير أي شي مثل this إلى React.لا تقلق، سنجيب عن هذا السؤال وأسئلة أخرى في صفحة الأسئلة الشائعة حول الخطافات.

إضافة: استعمال متغيرات حالة عديدة

التصريح عن متغيرات حالة كأزواج من [something, setSomething] هو أمر عملي وجيد، إذ يسمح لنا بإعطاء أسماء مختلفة لمتغيرات مختلفة للحالة إن أردنا استعمال أكثر من متغير حالة واحد:

function ExampleWithManyStates() {
  // التصريح عن متغيرات حالة عديدة
  const [age, setAge] = useState(42);
  const [fruit, setFruit] = useState('banana');
  const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);

في هذا المكون في الشيفرة الآنفة، لدينا المتغيرات age، و fruit، و todos بوصفها متغيرات حالة، ويمكننا تحديث كل منها على حدة:

function handleOrangeClick() {
    // this.setState({ fruit: 'orange' }) يشبه
    setFruit('orange');
  }

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

أعطينا الكثير من التوصيات حول فصل متغيرات الحالة المستقلة في صفحة الأسئلة الشائعة حول الخطافات.

الخطوات التالية

تعلمنا حول أحد الخطافات التي توفرها React وهو الخطاف useState. في أغلب الأحيان، سنشير إليه بالاسم "خطاف الحالة" (State Hook). يسمح لنا هذا الخطاف بإضافة حالة محلية إلى مكونات دالة في React بخطوات بسيطة وشيفرة أقل.

تعلمنا أيضًا القليل حول ماهية الخطافات. كما رأينا، الخطافات هي دوال تمكنك من "تعليق أو ربط" (hook into) ميزات React من مكونات دالة. أسماء الخطافات تبدأ دومًا بالكلمة use، وهنالك الكثير من الخطافات التي لم نرها بعد.

لنكمل الآن وننتقل إلى الخطاف التالي وهو الخطاف useEffect. يسمح لنا هذا الخطاف بتنفيذ تأثيرات جانبية (side effects) في المكونات، وهو يشبه توابع دورة الحياة في الأصناف.

 انظر أيضًا

 مصادر