العربية

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

خطافات React المخصصة: استخلاص منطق المكونات لإعادة الاستخدام

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

ما هي خطافات React المخصصة؟

في جوهرها، الخطاف المخصص هو دالة جافاسكريبت يبدأ اسمها بـ "use" ويمكنها استدعاء خطافات أخرى. يتيح لك استخلاص منطق المكونات في دوال قابلة لإعادة الاستخدام، وبالتالي القضاء على تكرار الكود وتعزيز بنية مكونات أنظف. على عكس مكونات React العادية، لا تعرض الخطافات المخصصة أي واجهة مستخدم؛ هي ببساطة تغلف المنطق.

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

لماذا نستخدم الخطافات المخصصة؟

فوائد استخدام الخطافات المخصصة عديدة:

إنشاء أول خطاف مخصص لك

دعنا نوضح إنشاء واستخدام خطاف مخصص بمثال عملي: جلب البيانات من واجهة برمجة تطبيقات (API).

مثال: useFetch - خطاف لجلب البيانات

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


import { useState, useEffect } from 'react';

function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const abortController = new AbortController();
    const signal = abortController.signal;

    const fetchData = async () => {
      setLoading(true);
      try {
        const response = await fetch(url, { signal: signal });
        if (!response.ok) {
          throw new Error(`HTTP error! Status: ${response.status}`);
        }
        const json = await response.json();
        setData(json);
        setError(null); // مسح أي أخطاء سابقة
      } catch (error) {
        if (error.name === 'AbortError') {
          console.log('Fetch aborted');
        } else {
          setError(error);
        }
        setData(null); // مسح أي بيانات سابقة
      } finally {
        setLoading(false);
      }
    };

    fetchData();

    return () => {
      abortController.abort(); // دالة التنظيف لإلغاء طلب الجلب عند إلغاء تحميل المكون أو تغيير عنوان URL
    };
  }, [url]); // إعادة تشغيل التأثير عند تغيير عنوان URL

  return { data, loading, error };
}

export default useFetch;

الشرح:

استخدام خطاف useFetch في مكون

الآن، دعنا نرى كيفية استخدام هذا الخطاف المخصص في مكون React:


import React from 'react';
import useFetch from './useFetch';

function UserList() {
  const { data: users, loading, error } = useFetch('https://jsonplaceholder.typicode.com/users');

  if (loading) return <p>Loading users...</p>;
  if (error) return <p>Error: {error.message}</p>;
  if (!users) return <p>No users found.</p>;

  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name} ({user.email})</li>
      ))}
    </ul>
  );
}

export default UserList;

الشرح:

أنماط متقدمة للخطافات المخصصة

إلى جانب جلب البيانات البسيط، يمكن استخدام الخطافات المخصصة لتغليف منطق أكثر تعقيدًا. فيما يلي بعض الأنماط المتقدمة:

1. إدارة الحالة باستخدام useReducer

لسيناريوهات إدارة الحالة الأكثر تعقيدًا، يمكنك دمج الخطافات المخصصة مع useReducer. يتيح لك ذلك إدارة انتقالات الحالة بطريقة أكثر تنظيمًا وقابلية للتنبؤ.


import { useReducer } from 'react';

const initialState = { count: 0 };

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}

function useCounter() {
  const [state, dispatch] = useReducer(reducer, initialState);

  const increment = () => dispatch({ type: 'increment' });
  const decrement = () => dispatch({ type: 'decrement' });

  return { count: state.count, increment, decrement };
}

export default useCounter;

الاستخدام:


import React from 'react';
import useCounter from './useCounter';

function Counter() {
  const { count, increment, decrement } = useCounter();

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </div>
  );
}

export default Counter;

2. التكامل مع السياق (Context) باستخدام useContext

يمكن أيضًا استخدام الخطافات المخصصة لتبسيط الوصول إلى سياق React. بدلاً من استخدام useContext مباشرة في مكوناتك، يمكنك إنشاء خطاف مخصص يغلف منطق الوصول إلى السياق.


import { useContext } from 'react';
import { ThemeContext } from './ThemeContext'; // بافتراض أن لديك ThemeContext

function useTheme() {
  return useContext(ThemeContext);
}

export default useTheme;

الاستخدام:


import React from 'react';
import useTheme from './useTheme';

function MyComponent() {
  const { theme, toggleTheme } = useTheme();

  return (
    <div style={{ backgroundColor: theme.background, color: theme.color }}>
      <p>This is my component.</p>
      <button onClick={toggleTheme}>Toggle Theme</button>
    </div>
  );
}

export default MyComponent;

3. تأخير التنفيذ (Debouncing) والتحكم في التردد (Throttling)

تأخير التنفيذ والتحكم في التردد هما تقنيتان تستخدمان للتحكم في معدل تنفيذ دالة ما. يمكن استخدام الخطافات المخصصة لتغليف هذا المنطق، مما يسهل تطبيق هذه التقنيات على معالجات الأحداث.


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

function useDebounce(value, delay) {
  const [debouncedValue, setDebouncedValue] = useState(value);

  useEffect(() => {
    const handler = setTimeout(() => {
      setDebouncedValue(value);
    }, delay);

    return () => {
      clearTimeout(handler);
    };
  }, [value, delay]);

  return debouncedValue;
}

export default useDebounce;

الاستخدام:


import React, { useState } from 'react';
import useDebounce from './useDebounce';

function SearchInput() {
  const [searchValue, setSearchValue] = useState('');
  const debouncedSearchValue = useDebounce(searchValue, 500); // تأخير التنفيذ لمدة 500 مللي ثانية

  useEffect(() => {
    // تنفيذ البحث باستخدام قيمة البحث المؤجلة
    console.log('Searching for:', debouncedSearchValue);
    // استبدل console.log بمنطق البحث الفعلي الخاص بك
  }, [debouncedSearchValue]);

  const handleChange = (event) => {
    setSearchValue(event.target.value);
  };

  return (
    <input
      type="text"
      value={searchValue}
      onChange={handleChange}
      placeholder="Search..."
    />
  );
}

export default SearchInput;

أفضل الممارسات لكتابة الخطافات المخصصة

لضمان فعالية وقابلية صيانة خطافاتك المخصصة، اتبع أفضل الممارسات التالية:

اعتبارات عالمية

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

مثال: تنسيق التاريخ الدولي باستخدام خطاف مخصص


import { useState, useEffect } from 'react';
import { DateTimeFormat } from 'intl';

function useFormattedDate(date, locale) {
  const [formattedDate, setFormattedDate] = useState('');

  useEffect(() => {
    try {
      const formatter = new DateTimeFormat(locale, {
        year: 'numeric',
        month: 'long',
        day: 'numeric',
      });
      setFormattedDate(formatter.format(date));
    } catch (error) {
      console.error('Error formatting date:', error);
      setFormattedDate('Invalid Date');
    }
  }, [date, locale]);

  return formattedDate;
}

export default useFormattedDate;

الاستخدام:


import React from 'react';
import useFormattedDate from './useFormattedDate';

function MyComponent() {
  const today = new Date();
  const enDate = useFormattedDate(today, 'en-US');
  const frDate = useFormattedDate(today, 'fr-FR');
  const deDate = useFormattedDate(today, 'de-DE');

  return (
    <div>
      <p>US Date: {enDate}</p>
      <p>French Date: {frDate}</p>
      <p>German Date: {deDate}</p>
    </div>
  );
}

export default MyComponent;

الخاتمة

تعتبر خطافات React المخصصة آلية قوية لاستخلاص منطق المكونات وإعادة استخدامه. من خلال الاستفادة من الخطافات المخصصة، يمكنك كتابة كود أنظف وأكثر قابلية للصيانة والاختبار. كلما أصبحت أكثر كفاءة في استخدام React، سيؤدي إتقانك للخطافات المخصصة إلى تحسين قدرتك بشكل كبير على بناء تطبيقات معقدة وقابلة للتطوير. تذكر أن تتبع أفضل الممارسات وتأخذ في الاعتبار العوامل العالمية عند تطوير الخطافات المخصصة لضمان فعاليتها وإمكانية وصولها لجمهور متنوع. احتضن قوة الخطافات المخصصة وارتقِ بمهاراتك في تطوير React!