استفاده از State Hook در React

مطلب قبلی 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>
  );
}

ما یادگیری Hook ها را با مقایسۀ این کد با یک مثال class معادل با آن شروع می‌کنیم.

مثال class معادل

اگر قبلا در ری اکت از class ها استفاده کرده باشید، این کد باید برایتان آشنا باشد:

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}

حالت (state) با { count: 0 } شروع شده و ما مقدار state.count را با هر کلیک کاربر و با فراخوانی this.setState() افزایش می‌دهیم. ما از قطعات این class در کل این صفحه استفاده خواهیم کرد.

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

Hook ها و کامپوننت های تابعی

به عنوان یادآوری، کامپوننت های تابعی در React چیزی شبیه این هستند:

const Example = (props) => {
  // You can use Hooks here!
  return <div />;
}

و یا این:

function Example(props) {
  // You can use Hooks here!
  return <div />;
}

احتمالا قبلا با اینها به عنوان کامپوننت های بدون حالت آشنا شده‌اید. اکنون ما توانایی استفاده از حالت React را از این کامپوننت ها معرفی می‌کنیم، بنابراین نام کامپوننت های تابعی را ترجیح می‌دهیم.

Hook ها داخل class ها کار نمی‌کنند. اما شما می‌توانید به جای نوشتن class ها از آنها استفاده کنید.

Hook چیست؟

مثال جدید ما با ایمپورت کردن هوک useState در ری اکت شروع می‌شود:

import { useState } from 'react';

function Example() {
  // ...
}

Hook چیست؟ یک Hook تابعی خاص است که به شما اجازه می‌دهد به قابلیت های ری اکت چنگ (قلاب یا Hook) بزنید. برای مثال useState یک Hook است که به شما اجازه می‌دهد حالت React را به کامپوننت های تابعی اضافه کنید. بعدا به Hook های دیگر نیز خواهیم پرداخت.

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

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

تعریف یک متغیر حالت

در یک class ما با تنظیم this.state به { count: 0 } در قسمت constructor، مقدار اولیۀ حالت count را صفر وارد می‌کنیم:

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

در یک کامپوننت تابعی ما this را نداریم در نتیجه نمی‌توانیم this.state را بخوانیم یا اختصاص دهیم. در مقابل، هوک useState را به طور مستقیم در کامپوننت خود فراخوانی می‌کنیم:

import { useState } from 'react';

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

فراخوانی useState چه کاری انجام می‌دهد؟ این کار یک متغیر حالت را تعریف می‌کند. متغیر ما count نامیده شده است ولی می‌توانست هر چیز دیگری مثلا banana باشد. این راهی برای حفظ برخی مقادیر بین فراخوانی های توابع است. useState راهی جدید برای استفاده از دقیقا همان قابلیتی است که this.state در class برایمان فراهم می‌کرد. به طور معمول وقتی تابع خارج می‌شود، متغیرها هم ناپدید می‌شوند، اما متغیرهای حالت توسط React حفظ می‌شوند.

ما چه چیزی را به عنوان آرگومان به useState منتقل می‌کنیم؟ تنها آرگومان منتقل شده به useState حالت اولیه است. برخلاف class ها، حالت نیازی نیست که حتما یک آبجکت باشد. ما می‌توانیم یک عدد یا یک رشته را نگه داریم، اگر آن تمام چیزی است که لازم داریم. در مثال ما، ما فقط تعداد دفعاتی که کاربر کلیک کرده است را می‌خواهیم، در نتیجه مقدار صفر را به عنوان حالت اولیه برای متغیرمان منتقل می‌کنیم. (اگر می‌خواستیم دو متغیر مختلف را در حالت ذخیره کنیم، می‌بایست دو مرتبه useState() را فراخوانی کنیم.)

useState چه چیزی را برمی‌گرداند؟ یک جفت مقدار را برمی‌گرداند: حالت کنونی و تابعی که آن را آپدیت می‌کند. به همین دلیل است که به شکل const [count, setCount] = useState() آن را نوشته‌ایم. این مشابه this.state.count و this.setState در یک class بوده با این تفاوت که آنها را در یک جفت زوج مولفه دریافت می‌کنید. اگر با سینتکسی که ما استفاده کرده‌اسم آشنا نیستید، در انتهای این صفحه به این موضوع برخواهیم گشت.

اکنون که می‌دانیم هوک useState چه کاری انجام می‌دهد، مثال ما می‌تواند بهتر معنی بدهد:

import { useState } from 'react';

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

ما یک متغیر حالت به نام count تعریف کردیم و آن را روی صفر تنظیم کردیم. ری اکت مقدار آن را در رندرهای مجدد در خاطر خواهد داشت و مقدار اخیر آن را در تابع ما مورد استفاده قرار خواهد داد. اگر می‌خواهیم count کنونی را تغییر دهیم، می‌توانیم setCount را فراخوانی کنیم.

نکته: ممکن است برای شما سوال باشد که چرا نام useState انتخاب شد و createState انتخاب نشد؟ چون نام Create (ساختن) چندان برای این موضوع دقیق نیست زیرا حالت در اولین مرتبه که کامپوننت ما رندر می‌شود ساخته شده است. حین رندرهای دیگر، useState به ما حالت کنونی را می‌دهد. در غیر این صورت اصلا حالت نمی‌بود. همچنین دلیل دیگری هم وجود دارد که چرا نام hook ها همیشه با use شروع می‌شود. دلیل آن را بعدا در بخش قوانین hook ها خواهیم دانست.

خواندن حالت

هنگامی که بخواهیم مقدار شمارنده کنونی را در یک class نمایش دهیم، this.state.count را می‌خوانیم:

<p>You clicked {this.state.count} times</p>

در یک تابع، می‌توانیم به طور مستقیم از count استفاده کنیم:

<p>You clicked {count} times</p>

آپدیت کردن حالت

در یک class، ما به فراخوانی this.setState() جهت آپدیت حالت count نیاز داریم:

<button onClick={() => this.setState({ count: this.state.count + 1 })}>
    Click me
  </button>

در یک تابع، ما setCount و count را به عنوان متغیر داریم در نتیجه به this نیاز نداریم:

<button onClick={() => setCount(count + 1)}>
    Click me
  </button>

خلاصه

اکنون بیایید چیزهایی که یاد گرفتیم را خط به خط خلاصه کنیم و یاد گرفته هایمان را چک کنیم.

import { useState } from 'react';

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

return (
     <div>
     <p>You clicked {count} times</p>
     <button onClick={() => setCount(count + 1)}>
       Click me
      </button>
      </div>
   );
}
  • خط ۱: ما هوک useState را از ری اکت ایمپورت کردیم. این کار به ما اجازه می‌دهد حالت محلی را در یک کامپوننت تابعی حفظ کنیم.
  • خط ۴: درون کامپوننت مثال ما، یک متغیر حالت جدید را با فراخوانی هوک useState تعریف کردیم. این یک زوج مقدار را متناظر با نام‌هایی که فراهم کرده‌ایم برمی‌گرداند.ما متغیر count خود را فراخوانی می‌کنیم چون تعداد کلیک‌ها را نگه می‌دارد. ما با منتقل کردن صفر به عنوان تنها آرگومان useState، مقدار اولیۀ آن را صفر تنظیم کردیم. آیتم دوم برگردانده شده خود یک تابع است و به ما اجازه می‌دهد شمارنده را آپدیت کنیم، لذا نام را setCount انتخاب کردیم.
  • خط ۹: وقتی کاربر کلیک کند، ما setCount را با مقداری جدید فراخوانی می‌کنیم. ری اکت کامپوننت مثال ما را رندر مجدد کرده و مقدار جدید شمارنده را به آن منتقل می‎کند.

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

کروشه ها به چه معنی هستند؟

حتما متوجه کروشه ها در تعریف یک متغیر حالت شده‌اید:

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

نام‌های سمت چپ، بخشی از API ری اکت نمی‌باشند. می‌توانید اسم دلخواه خودتان را برای متغیرهای حالت انتخاب کنید:

const [fruit, setFruit] = useState('banana');

این سینتکس جاوا اسکریپت تخریب آرایه نام دارد. این یعنی ما در حال ایجاد دو متغیر جدید fruit و setFruit هستیم که fruit تنظیم شده تا اولین مقدار برگردانده شده توسط useState باشد و setFruit مقدار دوم. این معادل کد زیر است:

var fruitStateVariable = useState('banana'); // Returns a pair
  var fruit = fruitStateVariable[0]; // First item in a pair
  var setFruit = fruitStateVariable[1]; // Second item in a pair

وقتی ما یک متغیر حالت را با useState تعریف کنیم، یک زوج به ما برمی‌گرداند، یعنی یک آرایه با دو آیتم. اولین آیتم، مقدار کنونی است و دومی یک تابع است که اجازه می‌دهد آن را آپدیت کنیم. استفاده از [۰] و [۱] جهت دسترسی به آنها کمی گیج کننده است چون آنها معنای خاصی دارند. به همین دلیل است که از تخریب آرایه استفاده می‌کنیم.

نکته: ممکن است کنجکاو باشید که ری اکت چگونه متوجه می‌شود که useState متناظر با کدام کامپوننت است، چون ما چیزی مانند this را به ری اکت برگشت نداده‌ایم. ما به این سوال و برخی سوالات مشابه در بخش پرسش‌های متداول پاسخ خواهیم داد.

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

تعریف متغیرهای حالت به صورت یک زوج [something, setSomething] از طرفی سودمند هم هست چون در صورتی که بخواهیم از بیش از یک متغیر حالت استفاده کنیم، به ما اجازه می‌دهد نام‌های متفاوتی را به متغیرهای حالت متفاوتی بدهیم:

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

در کامپوننت بالا، ما age و fruit و todos را به عنوان متغیرهای محلی داریم و می‌توانیم هر کدام از آنها را به طور مستقل آپدیت کنیم:

function handleOrangeClick() {
    // Similar to this.setState({ fruit: 'orange' })
    setFruit('orange');
  }

شما نباید از متغیرهای حالت زیادی استفاده کنید. متغیرهای حالت می‌توانند آبجکت ها و آرایه ها را به خوبی حفظ کنند، پس شما می‌توانید دیتاهای مرتبط به هم را گروه بنی کنید. هرچند برخلاف this.setState در یک class، آپدیت کردن یک متغیر حالت همیشه آن را جایگزین (replace) می‌کند، نه ادغام (merge).

ما توصیه های بیشتری را در مورد تقسیم متغیرهای حالت مستقل در بخش پرسش‌های متداول فراهم کرده‌ایم.

گام‌های بعدی

ما در این صفحه با یکی از Hook های فراهم شده توسط ری اکت یعنی useState آشنا شدیم. همینطور گاهی از آن با عنوان هوک حالت (State Hook) یاد می‌کنیم. این Hook به ما اجازه می‌دهد حالت محلی را به کامپوننت های تابعی React اضافه کنیم، کاری که برای اولین بار آن را انجام داده‌ایم.

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

اکنون بیایید با یک Hook دیگر آشنا شویم: useEffect. این Hook به شما اجازه می‌دهد اثرات جانبی (side effects) را در کامپوننت ها اجرا کنید و مشابه متدهای چرخۀ زندگی در class ها است.

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