ویجت‌ها در فلاتر: چرخه‌ی حیات

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

https://virgool.io/@shahpasand/%D9%88%DB%8C%D8%AC%D8%AA-%D9%87%D8%A7-%D8%AF%D8%B1-%D9%81%D9%84%D8%A7%D8%AA%D8%B1-%D9%85%D9%81%D8%A7%D9%87%DB%8C%D9%85-%D9%BE%D8%A7%DB%8C%D9%87-babfp7aaiii4

فرایند ایجاد و بروزرسانی ویجت‌ها، بارها و بارها در طول اجرای برنامه توسط فلاتر انجام می‌شود. بسته به نوع ویجت (Stateless یا Stateful)، متدهای متفاوتی اجرا خواهند شد اما چیزی که ثابت است این است که ما همیشه از فلاتر (به وسیله‌ی callback) نوتیفیکیشن دریافت می‌کنیم و این به ما کمک می‌کند تا رفتار ویجت را سفارشی کنیم. در ادامه چرخه‌ی حیات هر یک از انواع ویجت را بررسی خواهیم کرد.

ویجت‌های Stateless

متدهایی که در هنگام مدیریت ویجت‌های Stateless فراخوانی می‌شوند سرراست هستند:

1- برای شروع، سازنده‌ی ویجت فراخوانی می‌شود.

2- پس از اینکه سازنده اجرا شد، متد ()build بصورت خودکار توسط سیستم صدا زده می‌شود. این متد یک عنصر بصری جدید برمی‌گرداند که به درخت ویجت (در موقعیتی که آبجکت BuildContext که به عنوان پارامتر ورودی دریافت شده است، مشخص می‌کند) اضافه می‌شود .

class MyWidget extends StatelessWidget {
   //XXX: called 1st...
   MyWidget();
   //XXX: called 2nd...
   @override
   Widget build(BuildContext cntxt) {
       return Row(...);
   }
}

در نتیجه نمودار توالی ساده و به صورت زیر است:

چرخه‌ی حیات ویجت‌های Stateless
چرخه‌ی حیات ویجت‌های Stateless

ویجت های Stateful

  1. ابتدا سازنده‌ی ویجت (Stateful) فراخوانی می شود.
  2. سپس متد ()createState به صورت خودکار توسط سیستم فراخوانی می شود. این متد باید آبجکت state را که پشت این ویجت وجود دارد، نمونه سازی و ایجاد کند.
class MyOtherWidget extends StatefulWidget {
   MyOtherWidget();
   @override
   State createState() {
      return _MyOtherWidgetState();
   }
}
class _MyOtherWidgetState extends State<MyOtherWidget> {
     ...
}

به خاطر داشته باشید که ویجت‌های Stateful همواره دارای state (داده های پویایی که در طول زمان حیات ویجت آپدیت می شوند) هستند بنابراین به یک کلاس جدید نیاز است که آن را کپسوله سازی کند.

کلاس state که همواره از <>State ارث بری می کند، نوع ویجت را به عنوان یک پارامتر generic دریافت می‌کند. علاوه بر این، ویجت وابسته از طریق مشخصه‌ی widget در این کلاس قابل دسترسی است.

با این توضیح، نمودار این سناریو واضح خواهد بود:

چرخه‌ی حیات ویجت‌های Stateful
چرخه‌ی حیات ویجت‌های Stateful

اگر این نمودار را با نمودار قبل مقایسه کنید حتما این سوال برای شما پیش می آید که چه کسی مسئول ایجاد ویو برای ویجت خواهد یود؟ چون در حال حاضر فقط یک آبجکت state را ایجاد کرده ایم.

آبجکت State

آبجکت‌های State حاوی چندین متد در چرخه‌ی حیات خود هستند که یکی از آنها همان دوست قدیمی، متد ()build است:

class _MyOtherWidgetState extends State<MyOtherWidget> {
  @override
  Widget build(BuildContext cntxt) {
      return Column(...);
   }
}

بنابراین آبجکت‌های State در حقیقت مسئول ساخت واسط کاربری ویجت‌های وابسته به خود هستند. گرچه این ممکن است در ابتدا عجیب به نظر برسد، در نظر داشته باشید که آبجکت های State:

  • داده‌ی پویایی که ویجت نمایش خواهد داد را نگهداری می‌کنند
  • می توانند سیستم را وادار به ترسیم مجدد UI کنند

اینطور به موضوع نگاه کنید که تصمیم گیری در مورد چگونگی نمایش داده را انجام می‌دهند. برای مثال، وقتی یک آبجکت State یک مجموعه داده از اطلاعات کاربران را نگهداری می‌کند باید مشخص کند که واسط کاربری آن بصورت یک لیست است یا جدول.

جریان اجرا در چرخه حیات آبجکت state با فراخوانی متدها (یا callbackهای) زیر شکل می‌گیرد:

  1. مطابق معمول، سازنده‌ (آبجکت State) فراخوانی می‌شود. به محض اینکه اجرای سازنده با موفقیت پایان گرفت، ویجت وابسته، به درخت ویجت افزوده می‌شود و در وضعیتی با عنوان MOUNTED (یعنی یک BuildContext یا موقعیت مشخص در درخت دارد) قرار می‌گیرد.
  2. سپس ()initState یک بار و به صورت خودکار توسط سیستم فراخوانی می‌شود. این متد مکررا برای اجرای تسک‌های مقداردهی اولیه، مانند قالب‌بندی اطلاعات (format) برای نمایش و یا subscribe کردن به مخزن داده‌ای (data source) که آیتم‌های داده را منتشر می‌کند، مورد استفاده قرار می‌گیرد.
  3. سپس متد ()didChangeDependencies به طور خودکار توسط سیستم فراخوانی می‌شود. در این لحظه، ویجت DIRTY درنظر گرفته می‌شود، چرا که هنوز محتوای آن روی صفحه به نمایش درنیامده است (یعنی هنوز متد ()build اجرا نشده است).

نکته: اگر از مخزن داده استفاده کرده باشید، این متد هر گاه داده‌ی جدیدی منتشر شود فراخوانی خواهد شد. این یعنی بر خلاف ()initState این متد ممکن است بارها فراخوانی شود.

  1. سیستم متد ()build را فراخوانی می‌کند و واسط کاربری ساخته می‌شود. اکنون آبجکت CLEAN است.
  2. متد ()dispose هنگامی که ویجت از درخت ویجت حذف شد، به صورت خودکار توسط سیستم فراخوانی می‌شود. این متد غالبا برای آزادسازی منابع مورد استفاده قرار می‌گیرد برای مثال unsubscribe کردن از مخزن داده.

برای ویجت Stateful جریان‌های اجرای دیگری هم ممکن است اتفاق بیفتد:

  1. متد ()setState هر بار که آن را صریحا در کلاس State فراخوانی کنیم اجرا می‌شود. اجرای آن، ویجت را مجددا در وضعیت DIRTY قرار می‌دهد و سیستم را وادار می‌کند تا UI را مجدد ترسیم کند. این متد تفاوت اصلی ویجت های Stateful و Stateless محسوب می‌شود زیرا این امکان را فراهم می‌کند که برای ویجت خود، از سیستم درخواست آپدیت داشته باشیم. اجرای این متد معمولا در پی تعامل کاربر (مثلا کلیک روی یک دکمه) و برای بروزرسانی UI صورت می‌گیرد.
  2. متد ()didUpdateWidget هر بار که ویجت والد در درخت ویجت، محتوای خود را آپدیت می‌کند توسط سیستم فراخوانی می‌شود. ویجتی که به State وابسته است برچسب DIRTY می‌خورد و ترسیم مجدد آن در دستور کار قرار می‌گیرد.

اگر تمامی جریان های اجرا را در کنار هم بگذاریم و State های داخلی را هم درنظر بگیریم نمودار زیر را خواهیم داشت:

چرخه‌ی حیات آبجکت State
چرخه‌ی حیات آبجکت State

جمع‌بندی

  • چرخه‌ی حیات ویجت‌های Stateless تنها آبجکت معادل را ایجاد و UI آن را ترسیم می‌کند.
  • چرخه‌ی حیات ویجت‌های Stateful سازنده را فراخوانی می‌کند و آبجکت State را برای مدیریت داده‌های پویا مشخص می‌کند.
  • چرخه‌ی حیات آبجکت‌های State شامل چندین callback است. بروزرسانی و رفرش آبجکت می‌تواند توسط سیستم (وقتی عنصری که به آن وابسته هستیم تغییر می‌کند) و یا توسط خود آبجکت State درخواست شود.