في هذا الدرس 6تصفّح المواضيع
مع توسع تطبيق React وتعدد شاشاته، ستلاحظ تكرار نفس التركيبة البرمجية المكونة من useState() وuseEffect() في عدة مكونات: مثل جلب بيانات JSON مع إلغاء الطلبات، أو حفظ تفضيلات العرض في التخزين المحلي، أو تأخير استعلام البحث.
تمنحك React آلية أنيقة لاستخلاص هذا المنطق المتكرر داخل دالة JavaScript قابلة لإعادة الاستخدام تُسمى الخطاف المخصص (Custom Hook)؛ فبدلاً من نسخ 25 سطراً من كود الشبكة في خمسة ملفات، يستدعي المكون سطراً واحداً واضحاً ويتفرغ لرسم الواجهة.
يلتزم كل خطاف مخصص بقاعدة تسمية صارمة لا استثناء فيها: يجب أن يبدأ اسمه بالكلمة use متبوعة مباشرة بحرف لاتيني كبير، مثل useFetch وuseLocalStorage وuseDebounce.
لا تُعد هذه القاعدة تفضيلاً شكلياً فحسب؛ إذ تعتمد React وأداة الفحص الرسمية عليها لرصد أي دالة تحتوي بداخلها على خطافات والتأكد من عدم استدعائها داخل شرط if أو حلقة تكرار. وفي المقابل، فإن الدوال الحسابية العادية التي لا تستدعي أي خطاف مثل formatPrice() يجب ألا تبدأ ببادئة use.
لنجمع الآن خلاصة ما أتقنته في الدروس السابقة لبناء خطاف الجلب القياسي useFetch(url). داخل هذا الخطاف سندير متغيرات data وstatus وerror، وننشئ كائن new AbortController() داخل useEffect()، ونتحقق من response.ok مع استثناء AbortError.
لاحظ مدى نقاء وبساطة المكون المستدعي بعد هذا الاستخلاص؛ فمجرد تبديل الرابط بين الدورات والمنتجات يتكفل الخطاف تلقائياً بإلغاء الطلب القديم وتحديث الواجهة.
function useFetch(url) {
const [data, setData] = useState([]);
const [status, setStatus] = useState('loading');
useEffect(() => {
const ctrl = new AbortController();
// fetch with ctrl.signal + response.ok guard
return () => ctrl.abort();
}, [url]);
return { data, status };
}
يبرز خطافان مخصصان إضافيان في معظم مشاريع React الاحترافية:
- خطاف
useLocalStorage(key, initialValue): يستخدم دالة التهيئة الكسولة فيuseState()داخل كتلةtry / catchلقراءة تفضيلات العرض غير الحساسة (مثل نمط البطاقات المضغوط) ومزامنتها تلقائياً عند تغيرها. - خطاف
useDebounce(value, delayMs): يؤخر اعتماد النص المتغير السريع حتى يتوقف المستخدم عن الكتابة لمدةdelayMsمللي ثانية، فينسجم بسلاسة مع خطافuseFetch.
const [compact, setCompact] = useLocalStorage(
'rx-compact',
false
);
const [search, setSearch] = useState('');
const debounced = useDebounce(search, 250);
const url = `/api/products?q=${debounced}`;
const { data } = useFetch(url);
اجعل خطافاتك المخصصة مركزة حول غرض عملي واضح ومحدد مثل useFetch(url) أو useDebounce(text, 250)، وتجنب ابتكار أغلفة عامة فضفاضة مثل useMount(fn) تخفي مصفوفة الاعتماديات عن أدوات الفحص وتجعل تتبع الأخطاء أصعب. يلخص الجدول التالي أهم القواعد والأنماط:
| نمط الخطاف المخصص | الوظيفة الهندسية الأساسية | بنية الإرجاع الموصى بها |
|---|---|---|
| خطاف useFetch(url) | تغليف الجلب والإلغاء بـ AbortController وحالة الطلب | كائن مسمى: { data, status, error } |
| خطاف useLocalStorage | حفظ تفضيلات العرض غير الحساسة بأمان | مصفوفة ثنائية: [value, setValue] |
| خطاف useDebounce | تهدئة القيم النصية سريعة التغير قبل الجلب | القيمة المستقرة المفردة بعد المهلة |
| دالة formatCurrency | دالة تنسيق نقية لا تستدعي أي خطاف بداخلها | دالة عادية لا تبدأ ببادئة use |
ملخص الدرس
حصاد الدرسمراجعة مركّزة لأهم المفاهيم والقواعد الهندسية التي أتقنتها في هذا الدرس قبل التطبيق العملي
ماذا تعلّمت في هذا الدرس؟
تعلّمت في هذا الدرس استخلاص المنطق التفاعلي المتكرر في خطافات مخصصة تلتزم ببادئة use الإلزامية، وتحققت عملياً من عزل حالة كل مكون، وبنيت خطافات useFetch وuseLocalStorage وuseDebounce القابلة لإعادة الاستخدام. الخطوة التالية: انتقل الآن إلى الدرس رقم 42 «فهم أسباب إعادة التصيير وقياس الأداء في React» لمواصلة البناء التراكمي المتدرج في مسار React الحديث.
سجّل الدخول لحفظ تقدمك
تابع إنجاز المواضيع والمصطلحات والمهام، وكمّل من آخر خطوة على أي جهاز.
المصطلحات4
راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.
- 01 Custom Hook الخطاف المخصص
- دالة JavaScript تبدأ ببادئة use وتجمع خطافات React القياسية لتغليف منطق تفاعلي قابل لإعادة الاستخدام.
- للمراجعة
- 02 State Isolation عزل الحالة المستقل
- ضمان حصول كل مكون يستدعي نفس الخطاف المخصص على خلايا حالة وتأثيرات منفصلة ومستقلة تماماً.
- للمراجعة
- 03 Debouncing تهدئة المدخلات المتلاحقة
- تأجيل اعتماد القيمة المتغيرة بسرعة حتى تمر فترة سكون قصيرة دون إدخال جديد.
- للمراجعة
- 04 Lazy State Initializer التهيئة الكسولة للحالة
- تمرير دالة إلى useState بحيث لا تُقرأ بيانات localStorage إلا مرة واحدة عند التركيب الأول للمكون.
- للمراجعة
لا توجد بطاقات تطابق البحث والتصفية.
اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.
الاختصارات4
راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.
- 01 DRY DRY
- Don't Repeat Yourself
- مبدأ هندسي يقضي بمنع تكرار المنطق البرمجي عبر استخلاصه في وحدات نظيفة مثل الخطافات المخصصة.
- للمراجعة
- 02 API API
- Application Programming Interface
- يشير إلى نقاط اتصال الشبكة وكذلك إلى عقد المدخلات والمخرجات الواضح للخطاف المخصص.
- للمراجعة
- 03 AST AST
- Abstract Syntax Tree
- شجرة التحليل النحوي للكود التي تفحصها أدوات التدقيق للتأكد من التزام دوال use بقواعد الخطافات.
- للمراجعة
- 04 JSON JSON
- JavaScript Object Notation
- الصيغة النصية المستخدمة في useLocalStorage لحفظ واسترجاع قيم التفضيلات المهيكلة بأمان.
- للمراجعة
لا توجد بطاقات تطابق البحث والتصفية.
اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.
مهامك قبل الاختبار
خطوة صغيرة كل مرة. وإنجاز تقدر ترجع له.
-
افتح مثال عزل الحالة في محرر التجريب وزِد العداد الأول عدة مرات وتأكد من بقاء العداد الثاني مستقلاً عند 0.
-
افتح مثال SmartCatalog في محرر التجريب وبدّل نمط العرض المضغوط ثم ابحث عن "usb" لاختبار تكامل useLocalStorage مع useDebounce.
تأشير المهمة إقرار منك بإتمامها، وليس تصحيحًا آليًا للكود. يُحفظ تقدمك في حسابك.
اختبر فهمك.
ووصلها للإتقان.
كل سؤال خطوة لقدّام. اختار، اكتب كود، وشوف نتيجتك فورًا.
أكمل المهام، واجمع كل الإجابات الصحيحة. أقل من 100%؟ راجع وأعد المحاولة.
الأسئلة متاحة للاطلاع. سجّل الدخول للتفاعل وحفظ تقدمك.
لمحة عن التحدي10 أسئلة تنتظرك +
ما قاعدة التسمية الإلزامية التي يجب أن يلتزم بها كل خطاف مخصص في React؟
يجب أن يبدأ اسم دالة الخطاف المخصص بالكلمة use متبوعة بحرف كبير مثل useFetch.
عندما يستدعي مكونان منفصلان نفس الخطاف المخصص، فإنهما يتشاركان تلقائياً نفس قيمة الحالة.
خطأ؛ فالخطافات المخصصة تشارك المنطق فقط، بينما يحصل كل مكون على حالة مستقلة ومعزولة تماماً.
هل ينبغي تسمية دالة حسابية عادية مثل formatPrice لا تستدعي أي خطاف بداخلها بالاسم useFormatPrice؟
لا؛ فالدوال التي لا تستدعي خطافات بداخلها لا ينبغي أن تبدأ بـ use حتى يسهل استخدامها في أي موضع.
لماذا يدرج الخطاف المخصص useFetch(url) المعامل [url] في مصفوفة اعتماديات useEffect الداخلية؟
لكي يلغي الخطاف الطلب السابق تلقائياً ويجلب البيانات الجديدة بمجرد تغير رابط المورد.
تماماً كالخطافات المدمجة، لا يُستدعى الخطاف المخصص إلا في المستوى الأعلى للمكون أو لخطاف آخر ولا يوضع داخل شرط if.
صواب؛ تسري قواعد الخطافات بالكامل على جميع الخطافات المخصصة.
لماذا يضع خطاف useLocalStorage قراءة التخزين المحلي داخل دالة تهيئة كسولة في useState ومحاطة بـ try / catch؟
لقراءة التخزين مرة واحدة عند التركيب الأول، وحماية التطبيق من أخطاء JSON التالفة أو قيود التصفح الخاص.
ما المشكلة العملية التي يحلها الخطاف المخصص useDebounce(query, 250) عند ربطه بحقل بحث حي؟
ينتظر هدوء الكتابة لمدة 250 مللي ثانية قبل تحديث قيمة الاستعلام، فيمنع إطلاق طلب شبكة مع كل حرف منفرد.
يُعد خطاف useLocalStorage مثالياً لتفضيلات الواجهة غير الحساسة كالوضع المضغوط، ولا يُستخدم لتخزين رموز الجلسات السرية.
صواب؛ يُقصر التخزين المحلي على التفضيلات غير الحساسة بعيداً عن أسرار المصادقة.
متى يُفضل أن يعيد الخطاف المخصص كائناً مسمى { data, status, error } بدلاً من مصفوفة؟
عند إرجاع ثلاث قيم أو أكثر ليتمكن المستدعي من تفكيك الخصائص المطلوبة بالاسم دون التقيد بترتيب العناصر.
لماذا يحذّر توثيق React من ابتكار خطافات دورة حياة عامة فضفاضة مثل useMount(fn)؟
لأنها تخفي الاعتماديات التفاعلية عن أدوات الفحص وتسهّل الوقوع في أخطاء القيم المتقادمة.