نحوه تفکر صحیح درباره Hooks

در درس‌های قبلی این فصل، با چرایی وجود Hookها، قوانین اصلی آن‌ها و نمایی کلی از Hookهای اصلی React آشنا شدیم. در این درس آخر فصل پنجم، به یک سطح انتزاعی‌تر می‌رویم: چگونه باید به Hookها فکر کنیم تا استفاده از آن‌ها طبیعی و درست باشد، نه صرفاً حفظی؟

Hook یعنی «همگام‌سازی» با یک رندر، نه فقط یک تابع API

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

function Counter() {
  const [count, setCount] = useState(0);
  console.log("این خط، در هر رندر دوباره اجرا می‌شود");

  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}

در این مثال، خط console.log و فراخوانی useState، هر دو در هر رندر دوباره اجرا می‌شوند. تفاوت useState با یک متغیر معمولی این نیست که فقط یک‌بار اجرا می‌شود؛ تفاوت در این است که React مقدار State را بین رندرهای مختلف، به‌جای آن، نگه می‌دارد.

هر رندر، یک «عکس لحظه‌ای» جداگانه است

یک مدل ذهنی مفید این است که هر اجرای یک تابع کامپوننت را مانند یک عکس لحظه‌ای (Snapshot) از رابط کاربری، بر اساس State و Props همان لحظه، در نظر بگیریم. مقادیری که داخل یک Hook در طول یک رندر خاص خوانده می‌شوند (مثلاً count در مثال بالا)، متعلق به همان عکس لحظه‌ای هستند و در طول اجرای همان رندر، ثابت می‌مانند؛ حتی اگر بلافاصله بعد از آن، setCount فراخوانی شده باشد. این همان دلیلی است که در فصل سوم دیدیم چرا خواندن مقدار State بلافاصله پس از setCount، همچنان مقدار قدیمی را نشان می‌دهد.

ترتیب Hookها، هویت آن‌هاست

همان‌طور که در درس Rules of Hooks دیدیم، React برای تشخیص این‌که کدام State متعلق به کدام useState است، به ترتیب فراخوانی Hookها تکیه می‌کند، نه به نام متغیرها. دید درست این است که Hookها را نه به‌عنوان یک ابزار مستقل، بلکه به‌عنوان بخشی از یک دنباله ثابت و قابل‌پیش‌بینی در نظر بگیریم که در هر رندر، دقیقاً به همان شکل تکرار می‌شود.

هر Hook، یک قابلیت React را به کامپوننت متصل می‌کند

می‌توان هر Hook را دری در نظر گرفت که یک کامپوننت را به یک قابلیت خاص از React متصل می‌کند: useState به مکانیزم نگهداری State، useEffect به چرخه رندر و هماهنگی خارجی، useContext به داده‌ای که در سطح بالاتر تعریف شده است. با این دید، ترکیب چند Hook در یک کامپوننت، یعنی اتصال آن کامپوننت به چند قابلیت مختلف React، به‌طور هم‌زمان.

Custom Hooks: ترکیب Hookهای دیگر، نه چیزی جادویی

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

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

نمایش رفتار Snapshot در یک رندر
برای دیدن پیش‌نمایش کامپوننت، روی Run بزنید.

جمع‌بندی

تفکر درست درباره Hookها یعنی دیدن آن‌ها به‌عنوان بخشی از هر رندر، نه یک فراخوانی یک‌باره؛ هر رندر یک عکس لحظه‌ای مستقل از State و Props است، و ترتیب ثابت فراخوانی Hookها، همان چیزی است که به React اجازه می‌دهد هویت هر Hook را در طول رندرهای مختلف حفظ کند. با این مدل ذهنی، فصل پنجم به پایان می‌رسد و در ادامه به سراغ آزمون فصل ۵ می‌رویم.