Hook ها در یک نگاه

Hook (یا قلاب‌) قابلیتی است که در آینده نزدیک منتشر شده و به شما اجازه می‌دهد بدون نوشتن یک class از حالت یا قابلیت‌های دیگر React استفاده کنید. این قابلیت در حال حاضر در نسخۀ ۱۶.۷.۰-alpha ری اکت موجود است.

Hook ها صد در صد سازگاری عقبرو دارند. این صفحه شامل مطالبی جهت انجام یک مرور کلی بر Hook ها برای کاربران باتجربۀ ری اکت است و در واقع یک مرور سریع خواهیم داشت.

توضیح تفصیلی: جهت دانستن دلیل این که چرا Hooks را به ری اکت اضافه می‌کنیم، بخش مربوط به انگیزه که در صفحۀ قبلی موجود است را می‌توانید مطالعه کنید.

در پایان هر قسمت این صفحه، لینک‌هایی به توضیحات تفصیلی مرتبط با آن قسمت داده شده است.

State Hook

این مثال، یک شمارنده را رندر می‌کند. وقتی روی دکمه کلیک کنید، مقدار آن افزایش خواهد یافت:

import { useState } from 'react';

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

در اینجا، useState یک Hook است (بزودی در مورد این که این چه معنایی دارد صحبت خواهیم کرد). ما آن را داخل یک کامپوننت تابعی فراخوانی می‌کنیم تا برخی حالت محلی را به آن اضافه کنیم. ری اکت این حالت را در بین رندرهای مجدد حفظ خواهد کرد. useState یک زوج مولفه را برمی‌گرداند: مقدار حالت کنونی و تابعی که به شما اجازۀ آپدیت آن را می‌دهد. شما می‌توانید این تابع را از یک کنترل کنندۀ رویداد و یا هر جای دیگری فراخوانی کنید. این مشابه this.setState در یک class بوده با این تفاوت که حالت قدیمی و جدید را با هم ادغام نمی‌کند. (ما در بخش استفاده از State Hook مثالی از مقایسۀ useState با this.state نشان خواهیم داد.)

تنها آرگومان داخل useState حالت اولیه است. در مثال بالا، مقدار آن صفر است زیرا شمارندۀ ما از صفر شروع می‌شود. دقت کنید که بر خلاف this.state در اینجا حالت نیاز نیست که حتما یک آبجکت باشد، هرچند اگر بخواهید می‌تواند باشد. آرگومان حالت اولیه فقط حین اولین رندر مورد استفاده قرار می‌گیرد.

تعریف متغیرهای حالت چندگانه

شما می‌توانید بیش از یک بار در یک کامپوننت از State Hook استفاده کنید:

function ExampleWithManyStates() {
  // Declare multiple state variables!
  const [age, setAge] = useState(42);
  const [fruit, setFruit] = useState('banana');
  const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
  // ...
}

سینتکس تخریب آرایه به ما اجازه می‌دهد نام‌های مختلفی به متغیرهای حالتی که با فراخوانی useState تعریف کردیم بدهیم. این نام‌ها بخشی از API مربوط به useState نیستند. در مقابل، ری اکت فرض می‌کند که اگر شما useState را چندین بار فراخوانی کردید، این کار را در هر رندر در ترتیبی مشابه انجام خواهیم داد. ما در مورد اینکه چرا اینگونه عمل می‌کند و چه زمانی کاربرد دارد بعدا توضیح خواهیم داد.

پس Hook چیست؟

Hook ها توابعی هستند که به شما اجازه می‌دهند از کامپوننت های تابعی به حالت و چرخۀ زندگی ری اکت چنگ (قلاب یا Hook) بزنید. Hook ها داخل class ها کار نمی‌کنند، آنها به شما اجازه می‌دهند بدون استفاده از class ها از React استفاده کنید. (ما توصیه نمی‌کنیم یک شبه کامپوننت های موجود خود را بازنویسی کنید اما شما می‌توانید در کدهای جدید از آنها استفاده کنید.)

ری اکت چند Hook آماده مانند useState برایتان فراهم کرده است. همچنین شما می‌توانید Hook های متعلق به خود را جهت استفادۀ مجدد رفتار حالت دار بین کامپوننت های مختلف بسازید. ما در ابتدا به بررسی Hook های آماده می‌پردازیم.

توضیح تفصیلی: شما می‌توانید در مورد State Hook در صفحه‌ای که به آن اختصاص داده شده است بیشتر بدانید: استفاده از State Hook.

Effect Hook

حتما تا کنون گرفتن اطلاعات (data fetching)، عضوگیری و یا تغییر دستی DOM را از کامپوننت های React انجام داده‌اید. ما به این کارها، اثرات جانبی و یا به طور کوتاه effects (اثرات) می‌گوییم چون روی کامپوننت های دیگر تاثیر گذاشته و حین رندر قابل انجام نیستند.

useEffect که یک Effect Hook است، به ما این قابلیت را می‌دهد که اثرات جانبی را از یک کامپوننت تابعی اجرا کنیم و همان هدفی را دارد که componentDidMount و componentDidUpdate و componentWillUnmount در class های ری اکت دارند، اما در یک API تگ یکپارچه شده است. (ما مثال‌هایی از مقایسۀ useEffect با این متدها را در بخش استفاده از Effect Hook نشان خواهیم داد.)

برای مثال، این کامپوننت، پس از اینکه ری اکت DOM را آپدیت کرد، عنوان متن را تنظیم می‌کند:

import { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  // Similar to componentDidMount and componentDidUpdate:
  useEffect(() => {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

هنگامی که useEffect را فراخوانی می‌کنید، در واقع به ری اکت می‌گویید که تابع effect شما را پس از اعمال تغییر در DOM اجرا کند. effect ها داخل کامپوننت تعریف شده و در نتیجه به prop ها و حالت آن دسترسی دارند. به طور پیش‌فرض، ری اکت effect ها را پس از هر رندر اجرا می‌کند، که شامل اولین رندر نیز می‌شود. (ما در مورد مقایسۀ این با چرخه‌های زندگی class بعدا در بخش استفاده از Effect Hook صحبت خواهیم کرد.)

همچنین ممکن است effect ها چگونگی پاکسازی پس از آنها را با بازگرداندن یک تابع مشخص کنند. برای مثال، این کامپوننت از یک effect جهت اشتراک در وضعیت آنلاین بودن یک دوست استفاده می‌کند و پس از خارج شدن از آن، پاکسازی را انجام می‌دهد:

import { useState, useEffect } from 'react';

function FriendStatus(props) {
  const [isOnline, setIsOnline] = useState(null);

  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }

  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);

    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}

در این مثال، ری اکت از ChatAPI هنگامی که کامپوننت unmounts می‌گردد خارج شده و قبل از اجرای مجدد effect به خاطر یک رندر بعدی نیز همینطور. (اگر بخواهید، در صورتی که props.friend.id منتقل شده توسط ما به ChatAPI تغییر نکرد، راهی برای گفتن به ری اکت جهت skip کردن اشتراک مجدد دارید.)

درست مانند useState، شما می‌توانید بیش از یک بار در یک کامپوننت از یک effect استفاده کنید:

function FriendStatusWithCounter(props) {
  const [count, setCount] = useState(0);
  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  const [isOnline, setIsOnline] = useState(null);
  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }
  // ...

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

توضیح تفصیلی: شما می‌توانید در مورد useEffect در صفحه‌ای که به آن اختصاص داده شده است بیشتر بدانید: استفاده از Effect Hook.

قوانین Hooks

Hook ها توابع جاوا اسکریپت هستند، اما دو قانون اضافی هم اعمال می‌کنند:

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

ما یک پلاگین فراهم کرده‌ایم که به طور خودکار این قوانین را اعمال می‌کند. می‌دانیم که این قوانین در نظر اول ممکن است محدود کننده و دست و پا گیر باشند، اما برای درست کار کردن Hook ها لازم هستند.

توضیح تفصیلی: شما می‌توانید در مورد این قوانین در صفحه‌ای که به آن اختصاص داده شده است بیشتر بدانید: قوانین Hook ها.

ساخت Hook متعلق به خودتان

گاهی اوقات می‌خواهیم از برخی منطق های حالت دار بین کامپوننت ها استفادۀ مجدد کنیم. به طور معمول دو روش برای انجام این کار وجود داشت: کامپوننت های مرتبۀ بالاتر و prop های رندر. Hook های سفارشی به شما اجازۀ انجام این کار را بدون اضافه کردن کامپوننت هایی به درخت شما می‌دهند.

در اوایل این صفحه، کامپوننت FriendStatus را معرفی کردیم که Hook های useState و useEffect را جهت به اشتراک گذاری وضعیت آنلاین بودن یک دوست را فراخوانی می‌کند. فرض کنید می‌خواهیم از منطق به اشتراک گذاری این کامپوننت در کامپوننت دیگری استفادۀ مجدد کنیم.

ابتدا ما این های حالت دار را استخراج کرده و وارد یک Hook سفارشی به نام useFriendStatus می‌کنیم:

import { useState, useEffect } from 'react';

function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(null);

  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }

  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
    };
  });

  return isOnline;
}

این Hook به عنوان آرگومان friendID را گرفته و این که دوست ما آنلاین است یا خیر را برمی‌گرداند.

اکنون می‌توانیم از آن در هر دو کامپوننت ها استفاده کنیم:

function FriendStatus(props) {
  const isOnline = useFriendStatus(props.friend.id);

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}
function FriendListItem(props) {
  const isOnline = useFriendStatus(props.friend.id);

  return (
    <li style={{ color: isOnline ? 'green' : 'black' }}>
      {props.friend.name}
    </li>
  );
}

حالت این کامپوننت ها کاملا مستقل است. Hook ها راهی برای استفادۀ مجدد منطق حالت دار است، نه خود حالت. در حقیقت هر فراخوانی یک Hook یک حالت ایزولۀ کامل دارد، در نتیجه می‌توانید از یک Hook مشخص، دو بار در یک کامپوننت استفاده کنید.

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

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

توضیح تفصیلی: شما می‌توانید در مورد Hook های سفارشی در صفحه‌ای که به آن اختصاص داده شده است بیشتر بدانید: ساخت Hook متعلق به خودتان.

Hook های دیگر

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

function Example() {
  const locale = useContext(LocaleContext);
  const theme = useContext(ThemeContext);
  // ...
}

و useReducer به شما اجازه می‌دهد با کمک یک کاهنده، حالت محلی کامپوننت های پیچیده را مدیریت کنید:

function Todos() {
  const [todos, dispatch] = useReducer(todosReducer);
  // ...

توضیح تفصیلی: شما می‌توانید در مورد تمام Hook های از پیش تعریف شده و آماده در صفحه‌ای که به آن اختصاص داده شده است بیشتر بدانید: مرجع Hooks API.

گام‌های بعدی

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

همچنین می‌توانید مرجع Hooks API و پرسش و پاسخ‌های متداول Hook ها را بررسی کنید.

در نهایت، صفحۀ معرفی را هم از دست ندهید، چون در آنجا بیان کرده‌ایم که چرا Hook ها را اضافه کرده‌ایم و چگونه قصد داریم استفاده از آنها را در کنار class ها و بدون بازنویسی برنامه‌هایمان شروع کنیم.

1 Star2 Stars3 Stars4 Stars5 Stars (2 votes, average: 5٫00 out of 5)
Loading...
counter customizable free hit