درک مفهوم state و کار با آن + مدیریت رویدادها

Understand the Concept of state and Work with it + Event Management

23 بهمن 1399
درک مفهوم state و کار با آن + مدیریت رویداد ها

در قسمت قبل به طور کامل با خروجی های پویا و شیء props آشنا شدیم؛ در همان جلسه توضیح دادیم که چطور می توان از خارج از کامپوننت داده ها را تغییر داد اما برخی اوقات می خواهیم داده ها را از درون خود کامپوننت تغییر دهیم. در این قسمت با نحوه انجام این کار آشنا خواهیم شد.

فرض کنید در فایل App.js دکمه ای داشته باشیم که با فشردن آن یکی از نام ها تغییر کند:

class App extends Component {
  render() {
    return (
      <div className="App">
        <h1>Hi, I'm a React App!</h1>
        <p>This is really working!</p>
        <button>Switch Name</button>
        <Person name="Max" age="28" />
        <Person name="Manu" age="29" >My Hobbies: Racing</Person>
        <Person name="Stephanie" age="26" />
      </div>
    );
    // return React.createElement('div', {className: 'App'}, React.createElement('h1', null, 'Does this work now?'));
  }
}

کدنویسی عملکرد این دکمه را به جلسات بعد موکول می کنیم. در این جلسه می خواهیم کاری کنیم که نام های تعریف شده (Max و Manu و Stephanie) به صورت hardcode نوشته نشده باشند. hardcode یعنی نام را به صورت دستی بنویسیم و از هیچ متغیر یا عنصر پویایی استفاده نکنیم.

ما می توانیم از یک property خاص استفاده کنیم. توجه داشته باشید که این روش تنها زمانی کار می کند که کلاسی، کلاس Component را extend کند (یعنی کامپوننت های کلاس-محور نه کامپوننت های کاربردی) بنابراین نمی توان از این روش در کامپوننت Person استفاده کرد. نام این property خاص، state است.

نکته: در نسخه 16.8 کتابخانه react قابلیت جدیدی به نام hooks معرفی شده است که با آن می توان از state در کامپوننت های کاربردی نیز استفاده کرد! اما به دلیل راحتی در درک مسئله فعلا فرض را بر این می گذاریم که نسخه 16.8 ارائه نشده است. مطمئن باشید در رابطه با hooks بعدا به طور مفصل صحبت خواهیم کرد.

state در واقع یک شیء است که property های متخلفی را در خود نگه می دارد. شما می توانید هر نوع داده ای (آرایه، رشته و...) را در آن قرار دهید. ما می خواهیم state را به این صورت تعریف کنیم:

state = {
    persons: [
      { name: "Max", age: 28 },
      { name: "Manu", age: 29 },
      { name: "Stephanie", age: 26 }
    ]
  }

در واقع درون state یک آرایه به نام persons (شما می توانید هر نامی قرار دهید) ساخته ایم که شامل چند شیء جاوا اسکریپتی است. هر شیء که یک عضو این آرایه محسوب می شود اطلاعات افراد مختلف را درون خود دارد.

حالا می توانیم به شکل زیر به اطلاعات آن (یا هر property دیگری در یک کلاس جاوا اسکریپتی) دسترسی داشته باشیم:

<Person name={this.state.persons[0].name} age="28" />

this اشاره به کلاس App دارد (یعنی درون همین کلاسی که هستیم به دنبال فلان بگرد) بقیه کدها نیز جاوا اسکریپت ساده و عادی است که شما باید بلد باشید. حالا همین کار را برای بقیه افراد نیز انجام می دهیم:

class App extends Component {
  state = {
    persons: [
      { name: "Max", age: 28 },
      { name: "Manu", age: 29 },
      { name: "Stephanie", age: 26 }
    ]
  }

  render() {
    return (
      <div className="App">
        <h1>Hi, I'm a React App!</h1>
        <p>This is really working!</p>
        <button>Switch Name</button>
        <Person name={this.state.persons[0].name} age={this.state.persons[0].age} />
        <Person name={this.state.persons[1].name} age={this.state.persons[1].age} >My Hobbies: Racing</Person>
        <Person name={this.state.persons[2].name} age={this.state.persons[2].age} />
      </div>
    );
    // return React.createElement('div', {className: 'App'}, React.createElement('h1', null, 'Does this work now?'));
  }
}

حالا اگر فایل را ذخیره کنیم و به مرورگر برویم دکمه خودمان را می بینیم که فعلا هیچ کاری نمی کند و بقیه قسمت ها نیز دقیقا مانند قبل است.

خصوصیت state یک خصوصیت خاص است؛ از این جهت که اگر تغییری در آن ایجاد شود react تمام DOM را دوباره render می کند. state خاص است اما ما از آن به شکل خاصی استفاده نکرده ایم. برای این کار باید کدنویسی دکمه مان را نیز انجام دهیم.

برای کدنویسی دکمه باید از رویداد onclick استفاده کنیم. نکته بسیار مهم اینجاست که در جاوا اسکریپت و HTML عادی رویداد onclick به همین صورت (با c کوچک) نوشته می شود اما اگر بخواهید در JSX از آن استفاده کنید باید حتما از C بزرگ استفاده کنید. بنابراین:

<button onClick={}>Switch Name</button>

روش معمول برای کدنویسی این دکمه این است که یک متد (به زبان ساده، توابع در کلاس متد نام دارند) را به آن بدهیم. بنابراین باید یک متد تعریف کنیم. برای تعریف نام متدهای از این نوع از واژه Handler (به معنی «مدیریت کننده») در آخر نام متد استفاده می کنیم؛ این مسئله یک قرار داد است تا بگوید ما از این تابع به صورت عادی استفاده نمی کنیم مگر آنکه رویدادی اتفاق بیفتد. بنابراین الزامی برای پیروی از این روش ندارید اما ما از همین قرارداد استفاده می کنیم. ابتدا یک کد ساده درون متد خود قرار می دهیم تا از صحت آن مطمئن شویم:

switchNameHandler = () => {
    console.log('was clicked!');
  }

سپس این متد را به دکمه می دهیم:

<button onClick={this.switchNameHandler}>Switch Name</button>

نکته: هیچ گاه در انتهای نام متد خود پرانتز قرار ندهید. مثال:

<button onClick={this.switchNameHandler()}>Switch Name</button>

اگر چنین کاری انجام دهید، متد به صورت خودکار و بدون نیاز به کلیک، به محض render شدن DOM اجرا می شود.

حالا به مرورگر بروید و از قسمت developer tools (کلید f12) به سربرگ console بروید. با کلیک روی دکمه، باید عبارت !was clicked را مشاهده کنید.

حالا که از صحت عملکرد دکمه مطمئن شده ایم می توانیم کد دیگری به جای console بنویسیم:

switchNameHandler = () => {
    // console.log('was clicked!');
    this.state.persons[0].name = 'Maximilian';
  }

حالا اگر به مرورگر برویم و روی دکمه کلیک کنیم متوجه می شویم که هیچ تغییری ایجاد نمی شود! دلیل آن هم این است که mutate کردن (یعنی تغییر دادن) state به صورت مستقیم (مانند کد بالا) اشتباه است. بنابراین این دستور را هم کامنت می کنیم:

  switchNameHandler = () => {
    // console.log('was clicked!');
    // DON'T DO THIS: this.state.persons[0].name = 'Maximilian';
  }

برای تغییر state باید از تابعی از پیش تعریف شده در Component به نام setState استفاده کنیم. این متد به عنوان آرگومان یک شیء جاوا اسکریپتی می گیرد. سپس آن را با state قبلی خودمان ادغام می کند. بگذارید واضح تر توضیح دهم. فرض کنید state ما به این شکل باشد:

state = {
    persons: [
      { name: "Max", age: 28 },
      { name: "Manu", age: 29 },
      { name: "Stephanie", age: 26 }
    ],
    otherState: 'some other value'
  }

یعنی دو مقدار جداگانه داشته باشیم. سپس متد setState را نیز اینگونه بنویسیم:

switchNameHandler = () => {
    // console.log('was clicked!');
    // DON'T DO THIS: this.state.persons[0].name = 'Maximilian';
    this.setState({
      persons: [
        { name: "Maximilian", age: 28 },
        { name: "Manu", age: 29 },
        { name: "Stephanie", age: 27 }
      ]
    })
  }

یعنی property ای که قبلا داشتیم (persons) را با تغییراتی کوچک دوباره به آن بدهیم (نام Max را به Maximilian و سن Stephanie را به 27 سال تغییر داده ایم). در این حالت setState تفاوت های بین آرگومان خود و state قبلی را پیدا کرده و آن را اصلاح می کند اما آنقدر هوشمند است که به otherState دست نمی زند (چون آن را تغییر نداده ایم).

حالا اگر فایل را ذخیره کنیم و به مرورگر برگردیم، با فشردن دکمه متوجه تغییر مقادیر خواهیم شد. react متوجه شد که state تغییر کرده است بنابراین DOM را دوباره render کرد. دو عنصر در react به این شکل عمل می کنند: prop و state. هر زمان که یکی از اینها تغییر کند DOM نیز به روز رسانی می شود.

مفهوم کلی state به صورت خلاصه
مفهوم کلی state به صورت خلاصه

من یک فایل کمکی و خلاصه از توضیحات props و state برایتان آماده کرده ام که می توانید آن را نیز مطالعه کنید. دانلود فایل خلاصه درس.

امیدوارم به خوبی با state و props و تفاوت های آن ها آشنا شده باشید. در قسمت بعد به طور خلاصه در مورد hooks صحبت خواهیم کرد، اگر چه در انتهای دوره چند قسمت مفصل را به آن اختصاص می دهیم.

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری دوره جامع آموزش ری اکت توصیه می‌کند:
نویسنده شوید
دیدگاه‌های شما (1 دیدگاه)

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

شمه
20 مرداد 1400
سلام خسته نباشید بسیار عالی بود :)

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.