استخراج Logic قابل استفاده مجدد

در درس قبل دیدیم Custom Hook چیست و چطور ساخته می‌شود. سؤال مهم‌تر این است: چه منطقی ارزش دارد که به یک Custom Hook منتقل شود؟ هر تکه کدی را نباید به Hook تبدیل کرد. در این درس معیار تصمیم‌گیری و روش استخراج را بررسی می‌کنیم.

نشانه‌های یک منطق مناسب برای استخراج

معمولاً وقتی یک یا چند مورد از نشانه‌های زیر را ببینید، استخراج به Custom Hook منطقی است:

  • منطقی که شامل useState، useEffect یا Hook دیگری است و در چند کامپوننت تکرار شده است.
  • منطقی که با یک Effect و Cleanup به سیستم بیرونی (مثل رویداد مرورگر) وصل می‌شود و کامپوننت را شلوغ کرده است.
  • منطقی که نام مشخص و گویایی دارد؛ مثلاً «عرض پنجره»، «وضعیت آنلاین بودن» یا «مقدار یک input».

مثال: منطق عرض پنجره

فرض کنید چند کامپوننت باید عرض فعلی پنجره مرورگر را بدانند. بدون Custom Hook، هرکدام باید این منطق را کامل بنویسند:

function Header() {
  const [width, setWidth] = useState(window.innerWidth);

  useEffect(() => {
    function handleResize() {
      setWidth(window.innerWidth);
    }
    window.addEventListener("resize", handleResize);
    return () => window.removeEventListener("resize", handleResize);
  }, []);

  return <p>عرض: {width}</p>;
}

با استخراج، کل این منطق به یک تابع با نام گویا منتقل می‌شود:

function useWindowWidth() {
  const [width, setWidth] = useState(window.innerWidth);

  useEffect(() => {
    function handleResize() {
      setWidth(window.innerWidth);
    }
    window.addEventListener("resize", handleResize);
    return () => window.removeEventListener("resize", handleResize);
  }, []);

  return width;
}

function Header() {
  const width = useWindowWidth();
  return <p>عرض: {width}</p>;
}

حالا کامپوننت فقط می‌گوید «به عرض پنجره نیاز دارم» و جزئیات نحوه گرفتن آن داخل Hook پنهان است. این همان مزیت اصلی استخراج است: کامپوننت از «چگونه» جدا و به «چه چیزی» متمرکز می‌شود.

مراحل استخراج

روش استخراج معمولاً این مراحل را دارد:

  1. بخش تکراری را که شامل Hook است پیدا کنید.
  2. آن را داخل تابعی جدید با نامی که با use شروع می‌شود کپی کنید.
  3. هر مقداری که از بیرون لازم است را به‌عنوان پارامتر بگیرید.
  4. هر چیزی که کامپوننت لازم دارد را از تابع برگردانید.
  5. کد اولیه در کامپوننت را با فراخوانی Hook جایگزین کنید.

هر تابعی نباید Hook شود

اگر منطقی هیچ Hookی استفاده نمی‌کند (مثل جمع دو عدد یا قالب‌بندی یک تاریخ)، آن را با نام use نساخته و به‌عنوان یک تابع معمولی بنویسید. پیشوند use فقط برای تابعی است که واقعاً Hook فراخوانی می‌کند. نام‌گذاری اشتباه، ابزارها و هم‌تیمی‌هایتان را گمراه می‌کند.

استخراج زودهنگام هم مشکل‌ساز است

ساختن Hook برای منطقی که فقط یک‌بار و در یک‌جا استفاده شده، اغلب فقط لایه‌ای اضافی ایجاد می‌کند. بهتر است وقتی نیاز واقعی به استفاده مجدد یا خوانایی بیشتر دیده شد، آن را استخراج کنید، نه صرفاً به‌دلیل اینکه «Hook بهتر است».

مثال قابل اجرا

در این مثال، منطق نگه‌داری و تغییر مقدار یک input به یک Hook منتقل شده و دو فیلد از آن استفاده می‌کنند:

استخراج منطق input به useInput
برای دیدن پیش‌نمایش کامپوننت، روی Run بزنید.

جمع‌بندی

منطقی که شامل State یا Effect است، در چند کامپوننت تکرار می‌شود و نام گویایی دارد، کاندیدای خوبی برای استخراج به Custom Hook است. توابع بدون Hook باید تابع معمولی بمانند و استخراج زودهنگام هم فایده‌ای ندارد. در درس بعدی به طراحی API مناسب برای Custom Hookها می‌پردازیم.