سلام عزیزان ، به پارت هفتم از سری مقالات "مقدمات React" خوش اومدین . همونطور که میدونین در بخش قبلی به طور کامل با داده های پویا و آبجکت props آشنا شدیم و دیدیم که چطور میتونیم data ای رو از یک کامپوننت (کامپوننت والد) به یک کامپوننت دیگه (کامپوننت فرزند) انتقال بدیم . در کنار این موضوع ما گاهی اوقات نیاز داریم که داده ها رو از داخل خود کامپوننت تغییر بدیم و به همین دلیل در این بخش قرار هست که با نحوه ی انجام این کار و مفهوم state آشنا بشیم ! خوب بیاین شروع کنیم ...
در مرحله اول کامپوننت App رو به یک کامپوننت کلاس محور تبدیل میکنیم ( البته در نسخه ی 16.8 کتابخونه ی react ، قابلیت جدیدی به نام hooks معرفی شده که با استفاده از اون میتونیم از state در کامپوننت های تابعی هم استفاده کنیم ، ولی فعلا تمرکزمون رو میزاریم روی کامپوننت های کلاس محور ) :
در واقع state در واقع یک آبجکت هست که property های مختلفی رو در داخل خودش نگهداری میکنه و ما میتونیم هر نوع داده ای مثل آرایه ، رشته و . . . رو در داخلش قرار بدیم . در اصطلاح به مقادیری که state دریافت میکنه ، initial state یا state اولیه گفته میشه . اصولا ما state هارو در داخل کامپوننت والد تعریف میکنیم تا بتونیم از طریق props نتیجه رو به کامپوننت های فرزند یا زیر مجموعه هاش ارسال کنیم . ما به دو روش میتونیم state رو در کامپوننت های کلاس محور تعریف کنیم . روش اول این هست که state رو در داخل سازنده ی کلاس به اینصورت تعریف کنیم :
همونطور که میبینیم در داخل state یک آرایه به نام persons تعریف کردیم که اطلاعات افراد مختلف رو در داخل خودش نگهداری میکنه و شامل چند آبجکت هست که هر کدومشون به عنوان یک عضو این آرایه محسوب میشن . این مقدار میشه state اولیه یا حالت اولیه ی برنامه ی ما ! حالا برای اینکه بتونیم داده هایی که در داخل state تعریف کردیم رو به کامپوننت Person انتقال بدیم ، باید بصورت زیر عمل کنیم :
خوب ما به اینصورت تونستیم به اطلاعات state مون دسترسی داشته باشیم . در قطعه کد بالا کلمه ی کلیدی this به کلاس App اشاره میکنه (یعنی بهش میگیم داخل همین کلاسی که هستیم به دنبال فلان چیز بگرد) . حالا همین کارو برای سایر افراد هم انجام میدیم :
حالا اگر تغییرات رو ذخیره کنیم و به مرورگر بریم ، خواهیم دید که خروجی برنامه مون دقیقا مشابه حالت قبل هست :
اما این روش زیاد جالب نیست و کد تمیزی رو به ما ارائه نمیده ! برای رفع این مشکل میتونیم با استفاده از متد map رو آرایه ی persons حلقه بزنیم :
حالا بیایم با نحوه ی بروز رسانی state آشنا بشیم . فرض کنیم در کامپوننت App یک Button ای بصورت زیر داریم که میخوایم با کلیک کردن بر روی اون اسامی افراد تغییر کنه :
همونطور که گفتیم آبجکت state یک آبجکت خاص هست ، از این جهت که اگر تغییری در اون ایجاد بشه React مجددا عمل رندرینگ رو انجام میده و تنها اون بخشی از DOM که تغییر کرده رو برامون رندر میکنه ! برای اینکه بتونیم state مون رو بروزرسانی کنیم ، باید کدنویسی دکمه ی موردنظرمون رو هم انجام بدیم . به اینصورت که باید از رویداد استفاده کنیم تا هنگام کلیک کردن بر روی اون یک تابعی اجرا بشه ! چون همونطور که میدونیم تغییر state یک فرآیند هست و طبیعتا به کمک توابع میشه این کارو انجام داد . نکته ای که در اینجا باید بهش توجه کنیم این هست که در جاوااسکریپت و HTML عادی رویداد به همین صورت ( با c کوچیک ) نوشته میشه ، اما اگر بخوایم در JSX ازش استفاده کنیم باید حتما از C بزرگ استفاده کنیم ، بنابراین :
روش معمول برای کدنویسی این دکمه این هست که یک متد رو بهش پاس بدیم ، بنابراین باید یک متد تعریف کنیم . برای تعریف اسم متدهای از این نوع ، بهتره که در آخر اسم متد موردنظرمون از واژه ی Handler به معنی مدیریت کننده استفاده کنیم ، چون این یک قرارداد هست و میگه که ما از این تابع بصورت عادی استفاده نمیکنیم مگر اینکه رویدادی رخ بده ( بنابراین الزامی برای پیروی از این روش وجود نداره ) ! حالا در داخل متد موردنظرمون یک دستور log ساده قرار میدیم تا از نحوه ی عمل کردش مطمئن بشیم :
و بعد این متد رو بصورت زیر به دکمه ی موردنظرمون پاس میدیم :
به نکته ای که در اینجا باید بهش توجه کنیم این هست که هیچوقت نباید در انتهای اسم متد موردنظرمون پرانتز قرار بدیم ! چون اگر چنین کاری انجام بدیم ، متدمون به صورت خودکار و بدون نیاز به کلیک کردن و به محض render شدن DOM اجرا میشه ! حالا اگر به مرورگر بریم و از قسمت developer tools به سربرگ console بریم ، خواهیم دید که به ازای هر بار کلیک بر روی دکمه ی change ، عبارت !was clicked در کنسول چاپ میشه :
بعد از اینکه از صحت عملکرد دکمه مون مطمئن شدیم ، میتونیم بجای چاپ یک پیام ساده در کنسول ، کد دیگه ای رو بنویسیم :
حالا اگر به مرورگر بریم و روی دکمه Change کلیک کنیم ، متوجه میشیم که هیچ تغییری ایجاد نمیشه چونکه تغییر دادن state به صورت مستقیم (مثل کد بالا) کار درستی نیست ! برای اینکه بتونیم کد مربوط به تغییر state رو بطور صحیح بنویسیم ، باید از یک متد از پیش تعریف شده به نام setState استفاده کنیم ! این متد به عنوان آرگومان ورودی ، یک آبجکت رو دریافت میکنه و بعد اون رو با state قبلی مقایسه میکنه و چک میکنه که کدوم قسمت از state مون تغییر کرده و همون رو برامون بروزرسانی میکنه ! برای استفاده از setState باید بصورت زیر عمل کنیم :
همونطور که مشخصه ما در اینجا همون property ای که قبلا داشتیم یعنی persons رو با تغییرات کوچیکی به setState پاس دادیم ( نام Scott رو به Jack و سن David رو به 32 تغییر دادیم( . در این حالت setState تفاوت های بین آرگومان خودش و state قبلی رو پیدا میکنه و اون هارو بروزرسانی میکنه !
حالا اگر تغییرات رو ذخیره کنیم و به مرورگر برگردیم و روی دکمه Change کلیک کنیم ، متوجه تغییر مقادیر میشیم ، چون همونطور که گفته شد React متوجه تغییر state میشه و جاهایی که در DOM نیاز به تغییر دارن رو مجددا برای ما render میکنه :
حالا باید به چند نکته ی مهم توجه کنیم :
1. همونطور که گفته شد ما به دو روش میتونیم state رو در کامپوننت های کلاس محور تعریف کنیم که با روش اول یعنی تعریف state در داخل سازنده ی کلاس آشنا شدیم . روش دوم که برگرفته از ES7 و نوین تر هست ، به اینصورته که میتونیم state رو خارج از سازنده و بصورت زیر تعریف کنیم :
2. ما توابع Handler رو در کلاس کامپوننت ها به دو صورت میتونیم تعریف کنیم که تا اینجا با ساختار اول آشنا شدیم . حالا اگر تابع ( )personChangeHandler که بصورت Arrow Function تعریفش کردیم رو بصورت زیر تعریف کنیم ، هنگام کلیک بر روی دکمه ی Cahnge با خطا مواجه خواهیم شد ، چون در اینصورت باید this رو bind کنیم :
برای این منظور میتونیم بصورت زیر عمل کنیم :
حالا اگر مجددا تغییرات رو ذخیره کنیم و به مرورگر برگردیم و روی دکمه Change کلیک کنیم ، خواهیم دید که برنامه مون مشابه حالت قبل کار میکنه . در کل برای تعریف توابع Handler در کلاس کامپوننت ها ، بهتره از همون روش اول که برگرفته از ES7 هست استفاده کنیم !
خوب عزیزان این قسمت هم به پایان رسید ، امیدوارم تونسته باشم مفهوم state رو به خوبی براتون جا انداخته باشم . در رابطه با این مقاله اگر هر نوع سوال ، نظر یا انتقادی دارین ، خوشحال میشم که در قسمت کامنت ها باهام به اشتراک بزارین و به هر چه بهتر شدن مقالات کمک کنین .
پیشنهاد میکنم مواردی که تا به اینجا منتشر شدن رو حتما حتما مرور کنین و بعد بخشهای بعدی رو دنبال کنین ، چراکه میخوایم با هم از پایه یک مینی پروژه مفهومی رو تو چند پارت بصورت پیوسته توسعه بدیم تا هم پایه مون رو قوی تر کنیم و هم اینکه موارد جدیدتری رو یاد بگیریم !
میبینمتون :)