الخطافات المخصّصة: استخراج المنطق القابل لإعادة الاستخدام
انقل المنطق المعتمد على الحالة إلى دوال use* مخصّصة لمشاركة السلوك بين المكوّنات دون تكرار الشيفرة أو رفع الحالة.
الخطافات المخصّصة: استخراج المنطق القابل لإعادة الاستخدام درس مجاني في Frontend Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Frontend Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Frontend Academy 4 دروس في المجموع.
ما المقصود بـ Custom Hooks؟
الـ custom hook دالة JavaScript يبدأ اسمها بـ use وتستدعي Hooks أخرى داخليًا. تتيح لك custom hooks استخراج المنطق المعتمد على الحالة كي تشاركه عدة مكوّنات دون نسخ ولصق.
استخراج المنطق إلى Custom Hook
حدّد المنطق المكرر بين المكوّنات (الجلب + التحميل + الخطأ، وحجم النافذة، والتخزين المحلي) وانقله إلى custom hook.
function useWindowWidth() {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const handler = () => setWidth(window.innerWidth);
window.addEventListener('resize', handler);
return () => window.removeEventListener('resize', handler);
}, []);
return width;
}
// Usage:
const width = useWindowWidth();
const isMobile = width < 768;useFetch — Hook لجلب البيانات
Hook قابل لإعادة الاستخدام لجلب البيانات، ويمكن لأي مكوّن استخدامه لتحميل البيانات من عنوان URL.
function useFetch<T>(url: string) {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const controller = new AbortController();
async function load() {
try {
const res = await fetch(url, { signal: controller.signal });
if (!res.ok) throw new Error(`${res.status}`);
setData(await res.json());
} catch (err) {
if ((err as DOMException).name !== 'AbortError')
setError((err as Error).message);
} finally { setLoading(false); }
}
load();
return () => controller.abort();
}, [url]);
return { data, loading, error };
}Hook useLocalStorage
Hook مخصص يزامن قيمة مع localStorage ويحافظ على تزامنها بين علامات التبويب من خلال حدث storage.
function useLocalStorage<T>(key: string, initialValue: T) {
const [value, setValue] = useState<T>(() => {
const stored = localStorage.getItem(key);
return stored ? JSON.parse(stored) : initialValue;
});
const set = useCallback((newValue: T) => {
setValue(newValue);
localStorage.setItem(key, JSON.stringify(newValue));
}, [key]);
return [value, set] as const;
}تشارك Custom Hooks المنطق لا الحالة
يحصل كل مكوّن يستدعي custom hook على حالته المستقلة الخاصة. فالـ Hooks ليست مفردات — بل استدعاءات دوال تنشئ مثيلات حالة معزولة.
اصطلاحات التسمية
يجب أن تبدأ أسماء custom hooks بـ use. وتفرض ESLint ذلك من خلال قواعد فحص react-hooks، التي تضمن استدعاء Hooks في المستوى الأعلى وبالترتيب الصحيح.
إرجاع قيم متعددة
تعيد custom hooks عادةً كائنًا (بقِيَم مسمّاة) أو tuple (مثل useState). تتيح tuples تفكيك القيمة باستخدام أسماء مخصصة، بينما تكون الكائنات موضّحة لذاتها.
// Tuple (like useState):
const [value, setValue] = useLocalStorage('key', 0);
// Object (more descriptive):
const { data, loading, error, refetch } = useFetch('/api/users');Hook useDebounce
طبّق Debounce على قيمة: لا تحدّثها إلا بعد توقف المستخدم عن الكتابة لمدة تأخير محددة.
function useDebounce<T>(value: T, delay: number): T {
const [debounced, setDebounced] = useState(value);
useEffect(() => {
const timer = setTimeout(() => setDebounced(value), delay);
return () => clearTimeout(timer);
}, [value, delay]);
return debounced;
}
// Usage:
const debouncedSearch = useDebounce(searchTerm, 300);
useEffect(() => { search(debouncedSearch); }, [debouncedSearch]);Hook useMediaQuery
يغلّف window.matchMedia داخل Hook لقراءة نتائج استعلامات وسائط CSS بشكل تفاعلي.
function useMediaQuery(query: string): boolean {
const [matches, setMatches] = useState(() => window.matchMedia(query).matches);
useEffect(() => {
const mq = window.matchMedia(query);
const handler = (e: MediaQueryListEvent) => setMatches(e.matches);
mq.addEventListener('change', handler);
return () => mq.removeEventListener('change', handler);
}, [query]);
return matches;
}اختبار Custom Hooks
استخدم الأداة renderHook() من @testing-library/react لاختبار custom hooks بشكل مستقل دون تغليفها داخل مكوّن.
import { renderHook, act } from '@testing-library/react';
test('useCounter increments', () => {
const { result } = renderHook(() => useCounter(0));
expect(result.current.count).toBe(0);
act(() => result.current.increment());
expect(result.current.count).toBe(1);
});مكتبات Hooks المنشورة
توفر مكتبات Hooks المجتمعية مئات الـ Hooks المختبرة: @uidotdev/usehooks وreact-use وusehooks-ts. قبل كتابة custom hook، تحقّق من وجود إصدار مختبر جيدًا.
تحقق سريع
ماذا يحدث للحالة داخل custom hook عند استدعائه من مكوّنين مختلفين؟
مراجعة: Custom Hooks
تستخرج custom hooks المنطق المعتمد على الحالة لإعادة استخدامه. سمِّها بالبادئة use. ويحصل كل مكوّن يستدعي الـ Hook على حالة مستقلة. أعد كائنات أو tuples. ومن الأنماط الشائعة: useFetch وuseLocalStorage وuseDebounce وuseMediaQuery. اختبرها باستخدام renderHook(). وتحقق من مكتبات المجتمع قبل الكتابة من الصفر.
الأسئلة الشائعة
هل درس «الخطافات المخصّصة: استخراج المنطق القابل لإعادة الاستخدام» مجاني؟
نعم — نص درس «الخطافات المخصّصة: استخراج المنطق القابل لإعادة الاستخدام» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Frontend Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Frontend Academy 4 دروس في المجموع.
ماذا ستتعلم في «الخطافات المخصّصة: استخراج المنطق القابل لإعادة الاستخدام»؟
انقل المنطق المعتمد على الحالة إلى دوال use* مخصّصة لمشاركة السلوك بين المكوّنات دون تكرار الشيفرة أو رفع الحالة. تتمرن على Frontend Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Frontend Academy؟
لا تُشترط خبرة سابقة. Frontend Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.
كم من الوقت يستغرق درس «الخطافات المخصّصة: استخراج المنطق القابل لإعادة الاستخدام»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Frontend Academy هذا؟
نعم. كل درس في Frontend Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- useContext للحالة العامة
- useReducer للحالة المعقّدة
- useMemo وuseCallback لتحسين الأداء
- الخطافات المخصّصة: استخراج المنطق القابل لإعادة الاستخدام