الفرق بين المراجعتين لصفحة: «React/hooks overview»

من موسوعة حسوب
إنشاء الصفحة
 
اكمال إضافة الصفحة
سطر 1: سطر 1:
''الخطافات هي إضافة جديدة إلى الإصدار 16.8 في React، إذ تسمح لك باستعمال ميزة الحالة ومزايات React الأخرى دون كتابة أي صنف.''
<noinclude>{{DISPLAYTITLE:لمحة خاطفة عن الخطافات في React}}</noinclude>
''الخطافات هي إضافة جديدة إلى الإصدار 16.8 في React، إذ تسمح لك باستعمال ميزة الحالة وميزات React الأخرى دون كتابة أي صنف.''


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


'''شرح أوسع''': اقرأ القسم "[[React/hooks intro#.D8.A7.D9.84.D8.AD.D8.A7.D9.81.D8.B2 .D9.84.D8.A5.D8.B6.D8.A7.D9.81.D8.A9 .D8.A7.D9.84.D8.AE.D8.B7.D8.A7.D9.81.D8.A7.D8.AA|الحافز لإضافة الخطافات]]" لمعرفة سبب إضافة الخطافات إلى React.
'''شرح أوسع''': اقرأ القسم "[[React/hooks intro#.D8.A7.D9.84.D8.AD.D8.A7.D9.81.D8.B2 .D9.84.D8.A5.D8.B6.D8.A7.D9.81.D8.A9 .D8.A7.D9.84.D8.AE.D8.B7.D8.A7.D9.81.D8.A7.D8.AA|الحافز لإضافة الخطافات]]" لمعرفة سبب إضافة الخطافات إلى [[React]].


إذ تحوي مثل هذه الملاحظة الموجودة في نهاية كل قسم على رابط يحوي شرحًا موسَّعًا يمكن الرجوع إليه.
إذ تحوي مثل هذه الملاحظة الموجودة في نهاية كل قسم على رابط يحوي شرحًا موسَّعًا يمكن الرجوع إليه.


== خطاف الحالة ==
== خطاف الحالة ==
المثال التالي يصيِّر عدادًا، إذ ستزيد القيمة عند الضغط على الزر:<syntaxhighlight lang="javascript">
المثال التالي يصيِّر (render) عدادًا، إذ ستزيد قيمته عند الضغط على زر محدَّد:<syntaxhighlight lang="javascript">
import React, { useState } from 'react';
import React, { useState } from 'react';


function Example() {
function Example() {
   // Declare a new state variable, which we'll call "count"
   // "count" التصريح عن متغير حالة جديد ندعوه
   const [count, setCount] = useState(0);
   const [count, setCount] = useState(0);


سطر 24: سطر 25:
   );
   );
}
}
</syntaxhighlight>في هذه الشيفرة، <code>useState</code> هو خطاف (سنتحدث عن ما الذي يعينه هذا الأمر). نستدعي هذا الخطاف داخل مكون دالة لإضافة بعض الحالات المحلية إليه. ستحافظ React على هذه الحالة بين عمليات إعادة التصيير. يعيد <code>useState</code> زوجًا هو: قيمة الحالة الحالية ودالة تمكنك من تحديثها. يمكنك استدعاء هذه الدالة من معالج حدث أو أي مكان آخر. هي تشبه this.setState في صنف باستثناء أنها لا تدمج الحالة القديمة مع الحالة الجديدة. (سنظهر الفرق بين <code>useState</code> و <code>this.state</code> عبر مثال عملي في صفحة "[[React/hooks state|استعمال خطاف الحالة]]".)
</syntaxhighlight>في هذه الشيفرة، <code>useState</code> هو خطاف (سنتحدث عن ما الذي يعينه هذا الأمر). نستدعي هذا الخطاف داخل مكون دالة لإضافة بعض الحالات المحلية إليه. ستحافظ [[React]] على هذه الحالة بين عمليات إعادة التصيير. يعيد <code>useState</code> زوجًا هو: قيمة الحالة الحالية ودالة تمكنك من تحديثها. يمكنك استدعاء هذه الدالة من معالج حدث أو أي مكان آخر. هي تشبه <code>this.setState</code> في أي صنف باستثناء أنها لا تدمج الحالة القديمة مع الحالة الجديدة. (سنوضح الفرق بين <code>useState</code> و <code>this.state</code> عبر مثال عملي في صفحة "[[React/hooks state|استعمال خطاف الحالة]]".)


الوسيط الوحيد الذي يمكنك تمريره إلى useState هو الحالة الأولية. في المثال أعلاه، الحالة الأولية هي 0 لأننا افترضنا أن العداد يجب أن يبدأ العد من الصفر. لاحظ أنه بخلاف this.state، ليس اجباريًّا أن تكون الحالة هنا كائنًا رغم أنَّ تكون كذلك أن أردت أنت ذلك. وسيط الحالة الأولية يستعمل فقط في عملية التصيير الأولى.
الوسيط الوحيد الذي يمكنك تمريره إلى <code>useState</code> هو الحالة الأولية. في المثال أعلاه، الحالة الأولية هي <code>0</code> لأننا افترضنا أن العداد يجب أن يبدأ العد من الصفر. لاحظ أنه بخلاف <code>this.state</code>، ليس إجباريًّا أن تكون الحالة هنا كائنًا رغم أنَّ تكون كذلك أن أردت أنت ذلك. وسيط الحالة الأولية يستعمل فقط في عملية التصيير الأولى.


=== التصريح عن متغيرات عديدة للحالة ===
=== التصريح عن متغيرات عديدة للحالة ===
سطر 37: سطر 38:
   // ...
   // ...
}
}
</syntaxhighlight>تمكننا صيغة تفكيك المصفوفة من إعطاء أسماء مختلفة إلى متغيرات الحالة التي صرحنا عنها عبر استدعاء useState. هذه الأسماء ليست جزءًا من الواجهة useState البرمجية، ولكن React تفترض أنك إن استدعيت useState عدة مرات، فإنك تفعل ذلك بالترتيب نفسه خلال كل عملية تصيير. سنعود لاحقًا لمناقشة كيفية عمل هذا السلوك ومتى يكون استعماله مفيدًا.
</syntaxhighlight>تمكننا صيغة تفكيك المصفوفة من إعطاء أسماء مختلفة إلى متغيرات الحالة التي صرحنا عنها عبر استدعاء <code>useState</code>. هذه الأسماء ليست جزءًا من الواجهة <code>useState</code> البرمجية، ولكن [[React]] تفترض أنك إن استدعيت <code>useState</code> عدة مرات، فإنك تفعل ذلك بالترتيب نفسه خلال كل عملية تصيير. سنعود لاحقًا لمناقشة كيفية عمل هذا السلوك ومتى يكون استعماله مفيدًا.


=== ولكن ما هو الخطاف؟ ===
=== ولكن ما هو الخطاف؟ ===
الخطافات هي دوال تمكنك من "تعليق" (hook into) حالة React وميزات دورة الحياة من مكونات الدالة. لا تعمل الخطافات داخل الأصناف، إذ تمكنك من استعمال React دون الحاجة إلى الأصناف. (لا ننصح [[React/hooks intro#.D8.AE.D8.B7.D8.A9 .D8.A7.D9.84.D8.A7.D8.B9.D8.AA.D9.85.D8.A7.D8.AF .D8.A7.D9.84.D8.AA.D8.AF.D8.B1.D9.8A.D8.AC.D9.8A|بإعادة كتابة المكونات الحالية الخاصة بك]] بين عشية وضحاها ولكن ننصح ببدء استعمال الخطافات في المكونات الجديدة إن أردت ذلك.)
الخطافات هي دوال تمكنك من "تعليق" (hook into) حالة [[React]] وميزات دورة الحياة (lifecycle) من مكونات الدالة. لا تعمل الخطافات داخل الأصناف، إذ تمكنك من استعمال [[React]] دون الحاجة إلى الأصناف. (لا ننصح [[React/hooks intro#.D8.AE.D8.B7.D8.A9 .D8.A7.D9.84.D8.A7.D8.B9.D8.AA.D9.85.D8.A7.D8.AF .D8.A7.D9.84.D8.AA.D8.AF.D8.B1.D9.8A.D8.AC.D9.8A|بإعادة كتابة المكونات الحالية الخاصة بك]] بين عشية وضحاها ولكن ننصح ببدء استعمال الخطافات في المكونات الجديدة إن أردت ذلك.)


توفر React عددًا محدودًا من الخطافات المُضمَّنة مثل <code>useState</code>. يمكنك أيضًا إنشاء الخطافات الخاصة بك لإعادة استعمال سلوك ذي حالة بين مكونات مختلفة. سنتطرق أولًا إلى الخطافات المُضمَّنة في React.
توفر [[React]] عددًا محدودًا من الخطافات المُضمَّنة منها <code>useState</code>. يمكنك أيضًا إنشاء الخطافات الخاصة بك لإعادة استعمال سلوك ذي حالة بين مكونات مختلفة. سنتطرق أولًا إلى الخطافات المُضمَّنة في [[React]].


'''شرح أوسع''': يمكنك تعلم المزيد حول خطاف الحالة في توثيق مخصص به هو "[[React/hooks state|استعمال خطاف الحالة]]".
'''شرح أوسع''': يمكنك تعلم المزيد حول خطاف الحالة في توثيق مخصص به هو "[[React/hooks state|استعمال خطاف الحالة]]".


== خطاف التأثير ==
== خطاف التأثير ==
من المرجح أنك أجريت بعض عمليات جلب البيانات، أو الاشتراكات، أو تغير DOM يدويًا من مكونات React من قبل. نطلق على هذه العمليات بأنها عمليات تملك "تأثيرات جانبية" (side effects، أو "تأثيرات" فقط للاختصار) لأنها تستطيع أن تؤثر على مكونات أخرى ولا يمكن تنفيذها أثناء عملية التصيير.
من المرجح أنك أجريت بعض عمليات جلب البيانات، أو الاشتراكات، أو تغير DOM يدويًا من مكونات [[React]] من قبل. نُطلِق على هذه العمليات بأنَّها عمليات تملك "تأثيرات جانبية" (side effects، أو "تأثيرات" فقط للاختصار) لأنها تستطيع أن تؤثر على مكونات أخرى ولا يمكن تنفيذها أثناء عملية التصيير.


خطاف التأثير (Effect Hook) - الذي هو useEffect - يضيف القدرة على تنفيذ تأثيرات جانبية من مكون دالة. إنه يخدم الغرض ذاته الذي يفعله componentDidMount، و componentDidUpdate، و componentWillUnmount في أصناف React، ولكن في واجهة برمجية واحدة. (سنجرى عملية موازنة ونظهر الفرق بين useEffect وهذه التوابع مع أمثلة عملية في صفحة "[[React/hooks effect|استعمال خطاف التأثير]]".)
خطاف التأثير (Effect Hook) - الذي هو <code>useEffect</code> - يضيف القدرة على تنفيذ تأثيرات جانبية من مكون دالة. إنه يخدم الغرض ذاته الذي يفعله <code>componentDidMount</code>، و <code>componentDidUpdate</code>، و <code>componentWillUnmount</code> في أصناف [[React]]، ولكن في واجهة برمجية واحدة. (سنجرى عملية موازنة ونوضح الفرق بين <code>useEffect</code> وهذه التوابع مع أمثلة عملية في صفحة "[[React/hooks effect|استعمال خطاف التأثير]]".)


على سبيل المثال، المكون التالي يضبط عنوان الصفحة بعد تحديث React شجرة DOM:<syntaxhighlight lang="javascript">
على سبيل المثال، المكون التالي يضبط عنوان الصفحة بعد تحديث [[React]] شجرة DOM:<syntaxhighlight lang="javascript">
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect } from 'react';


سطر 72: سطر 73:
   );
   );
}
}
</syntaxhighlight>عند استدعاء useEffect، نخبر بذلك React بتنفيذ الدالة "effect" الخاصة بك بعد تطبيق التغييرات على الشجرة DOM. يُصرَّح عن التأثيرات داخل المكون، لذا يمكنها الوصول إلى خاصياته (props) وحالته (state). افتراضيًّا، تنفذ React التأثيرات بعد كل عملية تصيير بما فيها عملية التصيير الأولى. (سنتحدث بالتفصيل عن هذا السلوك مع موازنته مع سلوك دورات حياة صنف في الصفحة "[[React/hooks effect|استعمال خطاف التأثير]]".)
</syntaxhighlight>عند استدعاء <code>useEffect</code>، نخبر بذلك [[React]] بتنفيذ الدالة "<code>effect</code>" الخاصة بك بعد تطبيق التغييرات على الشجرة DOM. يُصرَّح عن التأثيرات داخل المكون، لذا يمكنها الوصول إلى خاصياته (props) وحالته (state). افتراضيًّا، تنفذ [[React]] التأثيرات بعد كل عملية تصيير بما فيها عملية التصيير الأولى. (سنتحدث بالتفصيل عن هذا السلوك مع موازنته مع سلوك دورات حياة صنف في الصفحة "[[React/hooks effect|استعمال خطاف التأثير]]".)


قد تحدِّد التأثيرات اختياريًّا كيفية إجراء عملية "تنظيف" بعد تنفيذها عبر إعادة دالة. على سبيل المثال، يستعمل المكون التالي تأثيرًا للاشتراك بحالة اتصال صديق (friend’s online status) ثم يجري عملية تنظيف عبر إلغاء الاشتراك منها:<syntaxhighlight lang="javascript">
قد تحدِّد التأثيرات اختياريًّا كيفية إجراء عملية "تنظيف" بعد تنفيذها عبر إعادة دالة. على سبيل المثال، يستعمل المكون التالي تأثيرًا للاشتراك بحالة اتصال صديق (friend’s online status) ثم يجري عملية تنظيف عبر إلغاء الاشتراك منها:<syntaxhighlight lang="javascript">
سطر 97: سطر 98:
   return isOnline ? 'Online' : 'Offline';
   return isOnline ? 'Online' : 'Offline';
}
}
</syntaxhighlight>في هذا المثال، ستلغي React الاشتراك من ChatAPI عند فصل (unmount) المكون وقبل إعادة تنفيذ التأثير نتيجة عملية التصيير اللاحقة. (إن أردت، هنالك طريقة لإخبار React بتخطي عملية إعادة الاشتراك إن لم يتغير props.friend.id الذي مررناه إلى ChatAPI.)
</syntaxhighlight>في هذا المثال، ستلغي [[React]] الاشتراك من <code>ChatAPI</code> عند فصل (unmount) المكون وقبل إعادة تنفيذ التأثير نتيجة عملية التصيير اللاحقة. (إن أردت، هنالك طريقة لإخبار [[React]] بتخطي عملية إعادة الاشتراك إن لم يتغير <code>props.friend.id</code> الذي مررناه إلى <code>ChatAPI</code>.)


بشكل مشابه للخطاف useState، تستطيع استعمال أكثر من تأثير في مكون:<syntaxhighlight lang="javascript">
بشكل مشابه للخطاف <code>useState</code>، تستطيع استعمال أكثر من تأثير في مكون:<syntaxhighlight lang="javascript">
function FriendStatusWithCounter(props) {
function FriendStatusWithCounter(props) {
   const [count, setCount] = useState(0);
   const [count, setCount] = useState(0);
سطر 120: سطر 121:
</syntaxhighlight>تسمح لك الخطافات بتنظيم التأثيرات الجانبية في مكون بناء على ترابط الأجزاء مع بعضها (مثل إضافة وإزالة اشتراك) عوضًا التقسيم الإجباري استنادًا إلى توابع دورة الحياة.
</syntaxhighlight>تسمح لك الخطافات بتنظيم التأثيرات الجانبية في مكون بناء على ترابط الأجزاء مع بعضها (مثل إضافة وإزالة اشتراك) عوضًا التقسيم الإجباري استنادًا إلى توابع دورة الحياة.


'''شرح أوسع''': يمكن تعلم المزيد حول الخطاف useEffect في صفحة مخصصة به هي "[[React/hooks effect|استعمال خطاف التأثير]]".
'''شرح أوسع''': يمكن تعلم المزيد حول الخطاف <code>useEffect</code> في صفحة مخصصة به هي "[[React/hooks effect|استعمال خطاف التأثير]]".


== قواعد تخص الخطافات ==
== قواعد تخص الخطافات ==
الخطافات هي دوال في جافاسكربت، ولكنها تفرض تطبيق قاعدتين إضافيتين هما:
الخطافات هي دوال في جافاسكربت، ولكنها تفرض تطبيق قاعدتين إضافيتين هما:
* تستدعى الخطافات فقط في المستوى الأعلى (top level). لا تستدعي الخطافات داخل حلقات تكرارية، أو شروط، أو دوال متشعبة.
* تُستدعَى الخطافات فقط في المستوى الأعلى (top level). بناءً على ذلك، لا تستدعي الخطافات داخل حلقات تكرارية، أو شروط، أو دوال متشعبة.
* تستدعى الخطافات فقط من مكونات دالة React (أي React function components). لا تستدعي الخطافات من دوال جافاسكربت العادية. (هنالك مكان آخر صالح يمكن استدعاء الخطافات منه يحدد عند بناء خطافات مخصصة خاصة بك. سنتحدث عن هذا النوع من الخطافات بعد قليل.)
* تُستدعَى الخطافات فقط من مكونات دالة [[React]] (أي React function components). لا تستدعي الخطافات من دوال جافاسكربت العادية. (هنالك مكان آخر صالح يمكن استدعاء الخطافات منه يحدد عند بناء خطافات مخصصة خاصة بك. سنتحدث عن هذا النوع من الخطافات بعد قليل.)
نوفر إضافة لاكتشاف أخطاء الصياغة يمكنها أن تطبق هاتين القاعدتين تلقائيًّا. نتفهَّم أن هاتين القاعدتين قد تبدوان لك مصدرًا لتقيد سلوك الخطافات أو قد تربكانك عند بدء استعمال الخطافات، ولكن كن على يقين أنَّهما ضروريتان لعمل الخطافات بشكل صحيح.
نوفر [https://www.npmjs.com/package/eslint-plugin-react-hooks إضافةً لاكتشاف أخطاء الصياغة] يمكنها أن تطبِّق هاتين القاعدتين تلقائيًّا. نتفهَّم أن هاتين القاعدتين قد تبدوان لك شكلًا من أشكال التقيد لسلوك الخطافات أو قد تسببان لك القلق عند بدء استعمال الخطافات، ولكن كن على يقين أنَّهما ضروريتان لعمل الخطافات بشكل صحيح.


'''شرح أوسع''': يمكن قراءة المزيد حول هاتين القاعدتين في صفحة "[[React/hooks rules|قواعد استعمال الخطافات]]".
'''شرح أوسع''': يمكن قراءة المزيد حول هاتين القاعدتين في صفحة "[[React/hooks rules|قواعد استعمال الخطافات]]".


== إنشاء خطافات مخصصة خاصة بك ==
== إنشاء خطافات مخصصة خاصة بك ==
بعض الأحيان، نحتاج إلى إعادة استعمال بعض المنطق ذي الحالة (stateful logic) بين المكونات. تقليديًّا، يوجد حلان لهذه المشكلة هما: [[React/higher order components|المكونات ذات الترتيب الأعلى]]، و<nowiki/>[[React/render props|خاصيات التصيير]]. تمكنك الخطافات المخصصة من إنجاز هذه المهمة، ولكن دون إضافة المزيد من المكونات إلى شجرتك.
بعض الأحيان، نحتاج إلى إعادة استعمال بعض الشيفرات ذات الحالة (stateful logic) بين المكونات. تقليديًّا، يوجد حلان لهذه المشكلة هما: [[React/higher order components|المكونات ذات الترتيب الأعلى]]، و<nowiki/>[[React/render props|خاصيات التصيير]]. تمكنك الخطافات المخصصة من إنجاز هذه المهمة، ولكن دون إضافة المزيد من المكونات إلى شجرتك.


في قسم سابق من هذه الصفحة، عرفنا المكون FriendStatus الذي يستدعي الخطاف useState والخطاف useEffect للاشتراك في حالة اتصال صديق. افترض أننا نريد أيضًا إعادة استعمال منطق هذا الاشتراك في مكون آخر فماذا نفعل؟
في قسم سابق من هذه الصفحة، عرفنا المكون <code>FriendStatus</code> الذي يستدعي الخطاف <code>useState</code> والخطاف <code>useEffect</code> للاشتراك في حالة اتصال صديق. افترض أننا نريد أيضًا إعادة استعمال شيفرة هذا الاشتراك في مكون آخر فماذا نفعل؟


أولًا، سنستخرج هذا المنطق إلى خطاف مخصص يدعى useFriendStatus بالشكل التالي:<syntaxhighlight lang="javascript">
أولًا، سنستخرج هذا الشيفرة إلى خطاف مخصص يدعى <code>useFriendStatus</code> بالشكل التالي:<syntaxhighlight lang="javascript">
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect } from 'react';


سطر 154: سطر 155:
   return isOnline;
   return isOnline;
}
}
</syntaxhighlight>يأخذ الوسيط friendID، ويعيد حالة الصديق أي إن كان متصلًا أم لا.
</syntaxhighlight>يأخذ الوسيط <code>friendID</code>، ويعيد حالة الصديق أي إن كان متصلًا أم لا.


الآن، يمكننا استعماله من أي مكون نريد:<syntaxhighlight lang="javascript">
الآن، يمكننا استعماله من أي مكون نريد:<syntaxhighlight lang="javascript">
سطر 175: سطر 176:
   );
   );
}
}
</syntaxhighlight>حالة هذه المكونات هي مستقلة كليًّا. الخطافات هي وسيلة لإعادة استعمال المنطق ذي الحالة وليس الحالة نفسها.  
</syntaxhighlight>حالة هذه المكونات هي مستقلة كليًّا. الخطافات هي وسيلة لإعادة استعمال الشيفرة ذات الحالة وليس الحالة نفسها. في الحقيقة، كل استدعاء إلى خطاف يملك حالة منعزلة تمامًا، لذا يمكنك حتى استعمال نفس الخطاف المخصص مرتين في مكون واحد.
 
الخطافات المخصصة هي أقرب للعرف من كونها ميزة. إن بدأ اسم دالة بالكلمة <code>use</code> واستدعت خطافات أخرى، نقول أنها "خطاف مخصص". التسمية <code>useSomething</code> المتعارف عليها هي التي تمكن [https://www.npmjs.com/package/eslint-plugin-react-hooks إضافة تصحيح أخطاء الصياغة] (linter plugin) من تنقيح الشيفرة التي تستعمل الخطافات.
 
يمكنك كتابة خطافات مخصصة تغطي مجالًا واسعًا من الحالات مثل معالجة النماذج، والتحريك، والاشتراكات التصريحية (declarative subscriptions)، والمؤقتات، وغيرها الكثير. نتشوَّق لرؤية الخطافات المخصصة التي سيبتكرها المجتمع.
 
'''شرح أوسع''': يمكنك تعلم المزيد حول الخطافات المخصصة بالتفصيل في صفحة "[[React/hooks custom|بناء خطافات خاصة بك]]".
 
== خطافات أخرى ==
هنالك بعض الخطافات المضمنة غير شائعة الاستخدام يمكن أن تجد فيها فائدةً ما. على سبيل المثال، <code>useContext</code> يسمح لك بالاشتراك بسياق React دون اللجوء إلى التشعب:<syntaxhighlight lang="javascript">
function Example() {
  const locale = useContext(LocaleContext);
  const theme = useContext(ThemeContext);
  // ...
}
</syntaxhighlight>والخطاف <code>useReducer</code> يمكنك من إدارة الحالة المحلية للمكونات المعقدة مع مخفِّض (reducer):<syntaxhighlight lang="javascript">
function Todos() {
  const [todos, dispatch] = useReducer(todosReducer);
  // ...
</syntaxhighlight>'''شرح أوسع''': يمكنك الاطلاع على جميع الخطافات المضمَّنة في التوثيق "[[React/hooks reference|مرجع إلى الواجهة البرمجية للخطافات]]".
 
== الخطوات التالية ==
كان هذا الشرح مختصرًا ومفيدًا، أليس كذلك؟! إن لم تعتقد ذلك أو كنت تريد تعلم المزيد وبالتفصيل، يمكنك الانتقال إلى الصفحات التالية بدءًا من توثيق "[[React/hooks state|استعمال خطاف الحالة]]".
 
يمكنك أيضًا في أي وقت الاطلاع على توثيق "[[React/hooks reference|مرجع إلى الواجهة البرمجية للخطافات]]" وصفحة "[[React/hooks faq|الأسئلة الشائعة حول الخطافات]]".
 
أخيرًا، إن لم تكن قد اطلعت على صفحة "[[React/hooks intro|مدخل إلى الخطافات]]"، فلا تدع فرصة قراءتها تفوتك، إذ تشرح تلك الصفحة سبب إضافة الخطافات  وكيفية البدء باستعمالها جنبًا إلى جنب مع الأصناف دون إعادة كتابة تطبيقك.


== انظر أيضًا ==
== انظر أيضًا ==
سطر 183: سطر 210:
* [[React/hooks effect|استعمال خطاف التأثير]]
* [[React/hooks effect|استعمال خطاف التأثير]]
* [[React/hooks rules|قواعد استعمال الخطافات]]
* [[React/hooks rules|قواعد استعمال الخطافات]]
* [[React/hooks custom|بناء خطاف خاص بك]]
* [[React/hooks custom|بناء خطافات خاصة بك]]
* [[React/hooks reference|مرجع إلى الواجهة البرمجية للخطافات]]
* [[React/hooks reference|مرجع إلى الواجهة البرمجية للخطافات]]
* [[React/hooks faq|الأسئلة الشائعة حول الخطافات]]
* [[React/hooks faq|الأسئلة الشائعة حول الخطافات]]
سطر 189: سطر 216:
== مصادر==
== مصادر==
*[https://reactjs.org/docs/hooks-overview.html صفحة لمحة خاطفة عن الخطافات في توثيق React الرسمي.]
*[https://reactjs.org/docs/hooks-overview.html صفحة لمحة خاطفة عن الخطافات في توثيق React الرسمي.]
[[تصنيف:React]]
[[تصنيف:React Hooks]]

مراجعة 11:54، 12 فبراير 2019

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

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

شرح أوسع: اقرأ القسم "الحافز لإضافة الخطافات" لمعرفة سبب إضافة الخطافات إلى React.

إذ تحوي مثل هذه الملاحظة الموجودة في نهاية كل قسم على رابط يحوي شرحًا موسَّعًا يمكن الرجوع إليه.

خطاف الحالة

المثال التالي يصيِّر (render) عدادًا، إذ ستزيد قيمته عند الضغط على زر محدَّد:

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>
  );
}

في هذه الشيفرة، useState هو خطاف (سنتحدث عن ما الذي يعينه هذا الأمر). نستدعي هذا الخطاف داخل مكون دالة لإضافة بعض الحالات المحلية إليه. ستحافظ React على هذه الحالة بين عمليات إعادة التصيير. يعيد useState زوجًا هو: قيمة الحالة الحالية ودالة تمكنك من تحديثها. يمكنك استدعاء هذه الدالة من معالج حدث أو أي مكان آخر. هي تشبه this.setState في أي صنف باستثناء أنها لا تدمج الحالة القديمة مع الحالة الجديدة. (سنوضح الفرق بين useState و this.state عبر مثال عملي في صفحة "استعمال خطاف الحالة".)

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

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

يمكنك استعمال خطاف الحالة (State Hook) أكثر من مرة مكون واحد بالشكل التالي:

function ExampleWithManyStates() {
  // Declare multiple state variables!
  const [age, setAge] = useState(42);
  const [fruit, setFruit] = useState('banana');
  const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
  // ...
}

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

ولكن ما هو الخطاف؟

الخطافات هي دوال تمكنك من "تعليق" (hook into) حالة React وميزات دورة الحياة (lifecycle) من مكونات الدالة. لا تعمل الخطافات داخل الأصناف، إذ تمكنك من استعمال React دون الحاجة إلى الأصناف. (لا ننصح بإعادة كتابة المكونات الحالية الخاصة بك بين عشية وضحاها ولكن ننصح ببدء استعمال الخطافات في المكونات الجديدة إن أردت ذلك.)

توفر React عددًا محدودًا من الخطافات المُضمَّنة منها useState. يمكنك أيضًا إنشاء الخطافات الخاصة بك لإعادة استعمال سلوك ذي حالة بين مكونات مختلفة. سنتطرق أولًا إلى الخطافات المُضمَّنة في React.

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

خطاف التأثير

من المرجح أنك أجريت بعض عمليات جلب البيانات، أو الاشتراكات، أو تغير DOM يدويًا من مكونات React من قبل. نُطلِق على هذه العمليات بأنَّها عمليات تملك "تأثيرات جانبية" (side effects، أو "تأثيرات" فقط للاختصار) لأنها تستطيع أن تؤثر على مكونات أخرى ولا يمكن تنفيذها أثناء عملية التصيير.

خطاف التأثير (Effect Hook) - الذي هو useEffect - يضيف القدرة على تنفيذ تأثيرات جانبية من مكون دالة. إنه يخدم الغرض ذاته الذي يفعله componentDidMount، و componentDidUpdate، و componentWillUnmount في أصناف React، ولكن في واجهة برمجية واحدة. (سنجرى عملية موازنة ونوضح الفرق بين useEffect وهذه التوابع مع أمثلة عملية في صفحة "استعمال خطاف التأثير".)

على سبيل المثال، المكون التالي يضبط عنوان الصفحة بعد تحديث React شجرة DOM:

import React, { useState, useEffect } from 'react';

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

  // Similar to componentDidMount and componentDidUpdate:
  useEffect(() => {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`;
  });

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

عند استدعاء useEffect، نخبر بذلك React بتنفيذ الدالة "effect" الخاصة بك بعد تطبيق التغييرات على الشجرة DOM. يُصرَّح عن التأثيرات داخل المكون، لذا يمكنها الوصول إلى خاصياته (props) وحالته (state). افتراضيًّا، تنفذ React التأثيرات بعد كل عملية تصيير بما فيها عملية التصيير الأولى. (سنتحدث بالتفصيل عن هذا السلوك مع موازنته مع سلوك دورات حياة صنف في الصفحة "استعمال خطاف التأثير".) قد تحدِّد التأثيرات اختياريًّا كيفية إجراء عملية "تنظيف" بعد تنفيذها عبر إعادة دالة. على سبيل المثال، يستعمل المكون التالي تأثيرًا للاشتراك بحالة اتصال صديق (friend’s online status) ثم يجري عملية تنظيف عبر إلغاء الاشتراك منها:

import React, { useState, useEffect } from 'react';

function FriendStatus(props) {
  const [isOnline, setIsOnline] = useState(null);

  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }

  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);

    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}

في هذا المثال، ستلغي React الاشتراك من ChatAPI عند فصل (unmount) المكون وقبل إعادة تنفيذ التأثير نتيجة عملية التصيير اللاحقة. (إن أردت، هنالك طريقة لإخبار React بتخطي عملية إعادة الاشتراك إن لم يتغير props.friend.id الذي مررناه إلى ChatAPI.) بشكل مشابه للخطاف useState، تستطيع استعمال أكثر من تأثير في مكون:

function FriendStatusWithCounter(props) {
  const [count, setCount] = useState(0);
  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  const [isOnline, setIsOnline] = useState(null);
  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }
  // ...

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

شرح أوسع: يمكن تعلم المزيد حول الخطاف useEffect في صفحة مخصصة به هي "استعمال خطاف التأثير".

قواعد تخص الخطافات

الخطافات هي دوال في جافاسكربت، ولكنها تفرض تطبيق قاعدتين إضافيتين هما:

  • تُستدعَى الخطافات فقط في المستوى الأعلى (top level). بناءً على ذلك، لا تستدعي الخطافات داخل حلقات تكرارية، أو شروط، أو دوال متشعبة.
  • تُستدعَى الخطافات فقط من مكونات دالة React (أي React function components). لا تستدعي الخطافات من دوال جافاسكربت العادية. (هنالك مكان آخر صالح يمكن استدعاء الخطافات منه يحدد عند بناء خطافات مخصصة خاصة بك. سنتحدث عن هذا النوع من الخطافات بعد قليل.)

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

شرح أوسع: يمكن قراءة المزيد حول هاتين القاعدتين في صفحة "قواعد استعمال الخطافات".

إنشاء خطافات مخصصة خاصة بك

بعض الأحيان، نحتاج إلى إعادة استعمال بعض الشيفرات ذات الحالة (stateful logic) بين المكونات. تقليديًّا، يوجد حلان لهذه المشكلة هما: المكونات ذات الترتيب الأعلى، وخاصيات التصيير. تمكنك الخطافات المخصصة من إنجاز هذه المهمة، ولكن دون إضافة المزيد من المكونات إلى شجرتك.

في قسم سابق من هذه الصفحة، عرفنا المكون FriendStatus الذي يستدعي الخطاف useState والخطاف useEffect للاشتراك في حالة اتصال صديق. افترض أننا نريد أيضًا إعادة استعمال شيفرة هذا الاشتراك في مكون آخر فماذا نفعل؟

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

import React, { useState, useEffect } from 'react';

function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(null);

  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }

  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
    };
  });

  return isOnline;
}

يأخذ الوسيط friendID، ويعيد حالة الصديق أي إن كان متصلًا أم لا. الآن، يمكننا استعماله من أي مكون نريد:

function FriendStatus(props) {
  const isOnline = useFriendStatus(props.friend.id);

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}
function FriendListItem(props) {
  const isOnline = useFriendStatus(props.friend.id);

  return (
    <li style={{ color: isOnline ? 'green' : 'black' }}>
      {props.friend.name}
    </li>
  );
}

حالة هذه المكونات هي مستقلة كليًّا. الخطافات هي وسيلة لإعادة استعمال الشيفرة ذات الحالة وليس الحالة نفسها. في الحقيقة، كل استدعاء إلى خطاف يملك حالة منعزلة تمامًا، لذا يمكنك حتى استعمال نفس الخطاف المخصص مرتين في مكون واحد.

الخطافات المخصصة هي أقرب للعرف من كونها ميزة. إن بدأ اسم دالة بالكلمة use واستدعت خطافات أخرى، نقول أنها "خطاف مخصص". التسمية useSomething المتعارف عليها هي التي تمكن إضافة تصحيح أخطاء الصياغة (linter plugin) من تنقيح الشيفرة التي تستعمل الخطافات.

يمكنك كتابة خطافات مخصصة تغطي مجالًا واسعًا من الحالات مثل معالجة النماذج، والتحريك، والاشتراكات التصريحية (declarative subscriptions)، والمؤقتات، وغيرها الكثير. نتشوَّق لرؤية الخطافات المخصصة التي سيبتكرها المجتمع.

شرح أوسع: يمكنك تعلم المزيد حول الخطافات المخصصة بالتفصيل في صفحة "بناء خطافات خاصة بك".

خطافات أخرى

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

function Example() {
  const locale = useContext(LocaleContext);
  const theme = useContext(ThemeContext);
  // ...
}

والخطاف useReducer يمكنك من إدارة الحالة المحلية للمكونات المعقدة مع مخفِّض (reducer):

function Todos() {
  const [todos, dispatch] = useReducer(todosReducer);
  // ...

شرح أوسع: يمكنك الاطلاع على جميع الخطافات المضمَّنة في التوثيق "مرجع إلى الواجهة البرمجية للخطافات".

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

كان هذا الشرح مختصرًا ومفيدًا، أليس كذلك؟! إن لم تعتقد ذلك أو كنت تريد تعلم المزيد وبالتفصيل، يمكنك الانتقال إلى الصفحات التالية بدءًا من توثيق "استعمال خطاف الحالة".

يمكنك أيضًا في أي وقت الاطلاع على توثيق "مرجع إلى الواجهة البرمجية للخطافات" وصفحة "الأسئلة الشائعة حول الخطافات".

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

انظر أيضًا

 مصادر