Kodokon kodokon.com

الخطّافات المخصصة: استخراج المنطق وإعادة استخدامه

استخرج المنطق ذا الحالة إلى خطّافات قابلة لإعادة الاستخدام والتركيب والاختبار.

8 دقيقة · 3 أسئلة

افتح هذا الدرس في Kodokon

الخطّاف المخصص دالة يبدأ اسمها بـ use وتستدعي خطّافات أخرى. يستخرج المنطق ذا الحالة، لا الحالة المشتركة: كل مكوّن يستدعيه يحصل على useState و useEffect خاصين به، معزولين تمامًا. إنه أداة React الأكثر مباشرة لتحليل المنطق - فحيث أضافت HOCs و render props طبقات إلى الشجرة، ينزلق الخطّاف إلى جسم المكوّن، ويُركَّب بسهولة، ويسهل اختباره.

JAVASCRIPT
import { useEffect, useState } from "react";

function useDebouncedValue(value, delay = 300) {
  const [debounced, setDebounced] = useState(value);

  useEffect(() => {
    const id = setTimeout(() => {
      setDebounced(value);
    }, delay);
    return () => clearTimeout(id);
  }, [value, delay]);

  return debounced;
}
التنظيف يلغي المؤقّت السابق في كل تغيير.

بادئة use ليست زخرفية: هي ما يتيح لإضافة ESLint المسماة react-hooks التحقق من قواعد الخطّافات داخل دالتك - استدعاءات غير مشروطة، في المستوى الأعلى. انتبه أيضًا لشكل الواجهة (API) المُرجَعة: صف [value, setValue] عندما يعكس الاستخدام useState، وكائن بمفاتيح مسمّاة بمجرد أن يكون هناك أكثر من شيئين لكشفهما.

JAVASCRIPT
function useLocalStorage(key, initialValue) {
  const [value, setValue] = useState(() => {
    const stored = localStorage.getItem(key);
    return stored !== null
      ? JSON.parse(stored)
      : initialValue;
  });

  useEffect(() => {
    localStorage.setItem(key, JSON.stringify(value));
  }, [key, value]);

  return [value, setValue];
}
تهيئة كسولة: لا يُقرأ localStorage إلا عند التركيب (mount).

الخطّافات تُركَّب: يمكن لخطّاف أن يستدعي خطّافات أخرى، بما فيها خطّافاتك أنت. هكذا تنشأ تجريدات أعمال قابلة للقراءة، مبنية على لبنات عامة. لاحظ اقتران AbortController بدالة التنظيف: دونه، قد يستجيب طلب أُطلق لإدخال أقدم بعد الأحدث ويطمس نتيجته - حالة السباق (race condition) الكلاسيكية في حقول البحث.

JAVASCRIPT
function useUserSearch(query) {
  const debounced = useDebouncedValue(query, 400);
  const [results, setResults] = useState([]);

  useEffect(() => {
    if (debounced === "") {
      setResults([]);
      return;
    }
    const controller = new AbortController();
    fetch("/api/search?q=" + debounced, {
      signal: controller.signal,
    })
      .then((res) => res.json())
      .then(setResults)
      .catch(() => {});
    return () => controller.abort();
  }, [debounced]);
  return results;
}
خطّاف الأعمال يُبنى على الخطّاف العام.

اختبار المعرفة

تأكّد من أنك تذكّرت النقاط الأساسية في هذا الدرس.

  1. ما وظيفة بادئة use في الخطّاف المخصص فعليًا؟
    • إنها اصطلاح تجميلي بحت موروث من الأصناف (classes)
    • تتيح للمُدقِّق اللغوي (linter) تمييز الدالة كخطّاف والتحقق من قواعد الخطّافات داخلها
    • ترفض React تشغيل دالة ذات حالة دون هذه البادئة
    • تُطلق الاستيراد التلقائي من react
  2. مكوّنان يستدعيان useLocalStorage بنفس المفتاح. هل يتشاركان حالتهما؟
    • نعم: يزامن الخطّاف تلقائيًا جميع مستدعيه
    • لا، وتُحفظ البيانات تحت مفتاحَي تخزين مختلفين
    • لا: كل استدعاء يملك حالته الخاصة في React؛ البيانات في localStorage وحدها هي المشتركة
  3. في useDebouncedValue، ما دور دالة التنظيف التي يُرجعها useEffect؟
    • إلغاء المؤقّت المعلّق كي لا تُنشر بعد المهلة سوى آخر قيمة أُدخلت
    • إعادة ضبط القيمة المُخمَّدة (debounced) في كل مرة يُفكَّك فيها المكوّن
    • منع إعادات تصيير المكوّن طوال مدة المهلة