Custom Hook چیست

در فصل‌های قبل با Hookهای آماده React مثل useState، useEffect، useRef، useContext و useReducer کار کردیم. اما React اجازه می‌دهد خودمان هم Hook بسازیم. در این فصل به Custom Hookها می‌پردازیم؛ ابزاری که کمک می‌کند منطق تکراری بین کامپوننت‌ها به‌شکل تمیز و قابل‌استفاده مجدد جمع شود.

مشکل: منطق تکراری در چند کامپوننت

فرض کنید در چند کامپوننت مختلف، به یک مقدار Boolean نیاز داریم که با یک تابع بین true و false جابه‌جا شود (مثلاً برای باز و بسته شدن یک منو، یک پنل یا یک پنجره). اگر هر بار همین منطق را از نو بنویسیم، کد تکراری می‌شود:

function Menu() {
  const [isOpen, setIsOpen] = useState(false);
  function toggle() {
    setIsOpen(!isOpen);
  }
  // ...
}

function Panel() {
  const [isOpen, setIsOpen] = useState(false);
  function toggle() {
    setIsOpen(!isOpen);
  }
  // ...
}

Custom Hook چیست

Custom Hook یک تابع جاوااسکریپت معمولی است که دو ویژگی دارد: نامش با use شروع می‌شود، و داخل آن می‌توان از Hookهای دیگر استفاده کرد. با این تابع می‌توانیم منطق مشترک را از کامپوننت‌ها بیرون بکشیم:

function useToggle(initialValue = false) {
  const [value, setValue] = useState(initialValue);

  function toggle() {
    setValue((prev) => !prev);
  }

  return [value, toggle];
}

حالا هر کامپوننت فقط یک خط می‌نویسد:

function Menu() {
  const [isOpen, toggle] = useToggle();
  // ...
}

چرا نام باید با use شروع شود

این فقط یک قرارداد ظاهری نیست. همان‌طور که در فصل پنجم درباره Rules of Hooks دیدیم، ابزارهایی مانند ESLint با دیدن پیشوند use تشخیص می‌دهند که این تابع Hook است و قوانین Hookها را برای آن بررسی می‌کنند. اگر نام تابع شما با use شروع نشود، این بررسی‌ها انجام نمی‌شود.

اشتراک منطق، نه اشتراک State

مهم‌ترین نکته درباره Custom Hookها این است که آن‌ها فقط منطق را به اشتراک می‌گذارند، نه State را. هر بار که یک کامپوننت یک Custom Hook را فراخوانی می‌کند، State و Effectهای داخل آن Hook، کاملاً مستقل و مخصوص همان کامپوننت هستند. اگر دو کامپوننت هر دو از useToggle استفاده کنند، هرکدام یک value جداگانه دارند و تغییر یکی روی دیگری اثر نمی‌گذارد. اگر قرار باشد State واقعاً بین کامپوننت‌ها مشترک باشد، باید از Lifting State Up یا Context استفاده کرد.

Custom Hook یک مکانیزم جادویی نیست

Custom Hook هیچ قابلیت جدیدی به React اضافه نمی‌کند. هر کاری که با آن انجام می‌دهید، با نوشتن مستقیم همان Hookها داخل کامپوننت هم ممکن بود؛ فایده آن، سازمان‌دهی، خوانایی و جلوگیری از تکرار است.

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

در این مثال، دو کامپوننت از یک Custom Hook استفاده می‌کنند. کلیک روی هر دکمه را امتحان کنید و ببینید State آن‌ها مستقل است.

useToggle و استقلال State هر فراخوانی
برای دیدن پیش‌نمایش کامپوننت، روی Run بزنید.

جمع‌بندی

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