Kodax

Custom Hooks - بناء Hooks مخصصة — مقدمة React

Custom Hooks

Custom Hooks تسمح لك باستخراج منطق المكون لإعادة استخدامه.

قواعد Custom Hooks

1. اسم الـ Hook يجب أن يبدأ بـ "use"

2. يمكنها استدعاء hooks أخرى

3. يجب استدعاؤها في مستوى أعلى (ليس داخل شروط أو loops)

مثال: useLocalStorage

function useLocalStorage(key, initialValue) {
  const [value, setValue] = useState(() => {
    try {
      const item = localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch {
      return initialValue;
    }
  });

  const setStoredValue = (newValue) => {
    setValue(newValue);
    localStorage.setItem(key, JSON.stringify(newValue));
  };

  return [value, setStoredValue];
}

// الاستخدام
function Settings() {
  const [theme, setTheme] = useLocalStorage('theme', 'light');
  
  return (
    <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
      الوضع: {theme}
    </button>
  );
}

مثال: useFetch

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

  useEffect(() => {
    const controller = new AbortController();
    
    setLoading(true);
    fetch(url, { signal: controller.signal })
      .then(res => res.json())
      .then(data => {
        setData(data);
        setLoading(false);
      })
      .catch(err => {
        if (err.name !== 'AbortError') {
          setError(err.message);
          setLoading(false);
        }
      });

    return () => controller.abort();
  }, [url]);

  return { data, loading, error };
}

// الاستخدام
function UsersList() {
  const { data: users, loading, error } = useFetch('/api/users');
  
  if (loading) return <p>جارٍ التحميل...</p>;
  if (error) return <p>خطأ: {error}</p>;
  
  return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
}
// useWindowSize - Hook لحجم النافذة
function useWindowSize() {
  const [size, setSize] = useState({
    width: window.innerWidth,
    height: window.innerHeight
  });

  useEffect(() => {
    const handleResize = () => {
      setSize({
        width: window.innerWidth,
        height: window.innerHeight
      });
    };

    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  return size;
}

// useToggle - Hook بسيط للتبديل
function useToggle(initialValue = false) {
  const [value, setValue] = useState(initialValue);
  const toggle = () => setValue(v => !v);
  return [value, toggle];
}

// الاستخدام
function Modal() {
  const [isOpen, toggleModal] = useToggle(false);
  const { width } = useWindowSize();
  
  return (
    <>
      <button onClick={toggleModal}>
        {isOpen ? 'إغلاق' : 'فتح'} Modal
      </button>
      {isOpen && (
        <div className={width < 768 ? 'modal-mobile' : 'modal-desktop'}>
          محتوى Modal
        </div>
      )}
    </>
  );
}
اختبر فهمك