انتقل إلى محتوى الدرس
الدرس 41
دورة ReactJS

بناء الخطافات المخصصة Custom Hooks لإعادة استخدام المنطقReusing Stateful Logic with Custom Hooks

استخلص المنطق التفاعلي المتكرر في خطافات React مخصصة تلتزم ببادئة use الإلزامية وتضمن عزل حالة كل مكون عبر بناء خطافات useFetch وuseLocalStorage وuseDebounce.
أقسام الدرس
6
الأمثلة
3
اللغة
العربية
تاريخ النشر
غير محدد
المشاهدات
0
محتوى الدرس
في هذا الدرس 6تصفّح المواضيع

مع توسع تطبيق React وتعدد شاشاته، ستلاحظ تكرار نفس التركيبة البرمجية المكونة من useState() وuseEffect() في عدة مكونات: مثل جلب بيانات JSON مع إلغاء الطلبات، أو حفظ تفضيلات العرض في التخزين المحلي، أو تأخير استعلام البحث.

تمنحك React آلية أنيقة لاستخلاص هذا المنطق المتكرر داخل دالة JavaScript قابلة لإعادة الاستخدام تُسمى الخطاف المخصص (Custom Hook)؛ فبدلاً من نسخ 25 سطراً من كود الشبكة في خمسة ملفات، يستدعي المكون سطراً واحداً واضحاً ويتفرغ لرسم الواجهة.

يلتزم كل خطاف مخصص بقاعدة تسمية صارمة لا استثناء فيها: يجب أن يبدأ اسمه بالكلمة use متبوعة مباشرة بحرف لاتيني كبير، مثل useFetch وuseLocalStorage وuseDebounce.

لا تُعد هذه القاعدة تفضيلاً شكلياً فحسب؛ إذ تعتمد React وأداة الفحص الرسمية عليها لرصد أي دالة تحتوي بداخلها على خطافات والتأكد من عدم استدعائها داخل شرط if أو حلقة تكرار. وفي المقابل، فإن الدوال الحسابية العادية التي لا تستدعي أي خطاف مثل formatPrice() يجب ألا تبدأ ببادئة use.

من أهم المفاهيم الهندسية التي ينبغي ترسيخها أن الخطافات المخصصة تشارك المنطق البرمجي ولا تشارك قيم الحالة نفسها. فعندما يستدعي مكونان مختلفان نفس الخطاف المخصص، لا يشتركان في متغير واحد؛ بل تخصص React لكل مكون خلايا useState() وuseEffect() مستقلة ومعزولة تماماً.

أما إذا أردت أن يقرأ مكونان شقيقان نفس قيمة الحالة المشتركة بالضبط، فارفع الحالة إلى الأب المشترك (Lifting State Up) أو مررها عبر السياق Context.

مخطط شجري يوضح كيف يزود الخطاف المخصص useFetch ثلاثة مكونات مختلفة بمنطق جلب موحد مع بقاء حالة كل مكون معزولة
HTML
function useStepCounter(initial = 0, step = 1) {
  const [count, setCount] = useState(initial);
  const increment = () => setCount((c) => c + step);
  const reset = () => setCount(initial);
  return { count, increment, reset };
}

لنجمع الآن خلاصة ما أتقنته في الدروس السابقة لبناء خطاف الجلب القياسي useFetch(url). داخل هذا الخطاف سندير متغيرات data وstatus وerror، وننشئ كائن new AbortController() داخل useEffect()، ونتحقق من response.ok مع استثناء AbortError.

لاحظ مدى نقاء وبساطة المكون المستدعي بعد هذا الاستخلاص؛ فمجرد تبديل الرابط بين الدورات والمنتجات يتكفل الخطاف تلقائياً بإلغاء الطلب القديم وتحديث الواجهة.

HTML
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.
HTML
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

راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.

0 / 4 مفهومةأول بطاقة، أول خطوة
01 Custom Hook الخطاف المخصص
دالة JavaScript تبدأ ببادئة use وتجمع خطافات React القياسية لتغليف منطق تفاعلي قابل لإعادة الاستخدام.
للمراجعة
02 State Isolation عزل الحالة المستقل
ضمان حصول كل مكون يستدعي نفس الخطاف المخصص على خلايا حالة وتأثيرات منفصلة ومستقلة تماماً.
للمراجعة
03 Debouncing تهدئة المدخلات المتلاحقة
تأجيل اعتماد القيمة المتغيرة بسرعة حتى تمر فترة سكون قصيرة دون إدخال جديد.
للمراجعة
04 Lazy State Initializer التهيئة الكسولة للحالة
تمرير دالة إلى useState بحيث لا تُقرأ بيانات localStorage إلا مرة واحدة عند التركيب الأول للمكون.
للمراجعة

اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.

حروف قليلة. معنى كامل.

الاختصارات4

راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.

0 / 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/2مهام منجزة
  1. افتح مثال عزل الحالة في محرر التجريب وزِد العداد الأول عدة مرات وتأكد من بقاء العداد الثاني مستقلاً عند 0.

  2. افتح مثال SmartCatalog في محرر التجريب وبدّل نمط العرض المضغوط ثم ابحث عن "usb" لاختبار تكامل useLocalStorage مع useDebounce.

تأشير المهمة إقرار منك بإتمامها، وليس تصحيحًا آليًا للكود. يُحفظ تقدمك في حسابك.

مساحة التحدي

اختبر فهمك.
ووصلها للإتقان.

كل سؤال خطوة لقدّام. اختار، اكتب كود، وشوف نتيجتك فورًا.

10أسئلة 2أنواع تحديات 100%هدف الإتقان
تصحيح تلقائي. فرص بلا حدود.

أكمل المهام، واجمع كل الإجابات الصحيحة. أقل من 100%؟ راجع وأعد المحاولة.

الأسئلة متاحة للاطلاع. سجّل الدخول للتفاعل وحفظ تقدمك.

لمحة عن التحدي10 أسئلة تنتظرك
01

ما قاعدة التسمية الإلزامية التي يجب أن يلتزم بها كل خطاف مخصص في React؟

يجب أن يبدأ اسم دالة الخطاف المخصص بالكلمة use متبوعة بحرف كبير مثل useFetch.

02

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

خطأ؛ فالخطافات المخصصة تشارك المنطق فقط، بينما يحصل كل مكون على حالة مستقلة ومعزولة تماماً.

03

هل ينبغي تسمية دالة حسابية عادية مثل formatPrice لا تستدعي أي خطاف بداخلها بالاسم useFormatPrice؟

لا؛ فالدوال التي لا تستدعي خطافات بداخلها لا ينبغي أن تبدأ بـ use حتى يسهل استخدامها في أي موضع.

04

لماذا يدرج الخطاف المخصص useFetch(url) المعامل [url] في مصفوفة اعتماديات useEffect الداخلية؟

لكي يلغي الخطاف الطلب السابق تلقائياً ويجلب البيانات الجديدة بمجرد تغير رابط المورد.

05

تماماً كالخطافات المدمجة، لا يُستدعى الخطاف المخصص إلا في المستوى الأعلى للمكون أو لخطاف آخر ولا يوضع داخل شرط if.

صواب؛ تسري قواعد الخطافات بالكامل على جميع الخطافات المخصصة.

06

لماذا يضع خطاف useLocalStorage قراءة التخزين المحلي داخل دالة تهيئة كسولة في useState ومحاطة بـ try / catch؟

لقراءة التخزين مرة واحدة عند التركيب الأول، وحماية التطبيق من أخطاء JSON التالفة أو قيود التصفح الخاص.

07

ما المشكلة العملية التي يحلها الخطاف المخصص useDebounce(query, 250) عند ربطه بحقل بحث حي؟

ينتظر هدوء الكتابة لمدة 250 مللي ثانية قبل تحديث قيمة الاستعلام، فيمنع إطلاق طلب شبكة مع كل حرف منفرد.

08

يُعد خطاف useLocalStorage مثالياً لتفضيلات الواجهة غير الحساسة كالوضع المضغوط، ولا يُستخدم لتخزين رموز الجلسات السرية.

صواب؛ يُقصر التخزين المحلي على التفضيلات غير الحساسة بعيداً عن أسرار المصادقة.

09

متى يُفضل أن يعيد الخطاف المخصص كائناً مسمى { data, status, error } بدلاً من مصفوفة؟

عند إرجاع ثلاث قيم أو أكثر ليتمكن المستدعي من تفكيك الخصائص المطلوبة بالاسم دون التقيد بترتيب العناصر.

10

لماذا يحذّر توثيق React من ابتكار خطافات دورة حياة عامة فضفاضة مثل useMount(fn)؟

لأنها تخفي الاعتماديات التفاعلية عن أدوات الفحص وتسهّل الوقوع في أخطاء القيم المتقادمة.