توی ReArch دو نوع شنونده داریم:
- شنوندههای موقتی که وقتی دیگه نیازی بهشون نیست بهصورت دستی حذف میشن
- شنوندههایی که تا وقتی خود کانتینر زندهست، زنده میمونن (مثلاً برای یه لاگر)
نوع اول شنونده از طریق متد listen که روی کانتینرها وجود داره مدیریت میشه،
و توی کانتینرها توضیح داده شده.
نوع دوم چیزیه که این صفحه بهش میپردازه.
برای پیادهسازی یه شنونده بلندمدت،
فقط کافیه یه کپسول جدید بسازی (با یه تغییر کوچیک—ادامه رو بخون)!
اولین تلاشت (که اشتباهه) ممکنه چیزی شبیه این باشه:
/// یه کپسول شنونده که به یه سری کپسول دیگه گوش میده.
/// توجه کن به نوع بازگشتی `void`؛
/// شنوندهها فقط به دادههای دیگه گوش میدن و چیزی برنمیگردونن.
/// هشدار: این (یه کم) اشتباهه! برای اطلاعات بیشتر ادامه رو بخون.
void myListener(CapsuleHandle use) {
print(use(foobarCapsule));
}
// توی تابع main() یا یه جای مشابه،
// شنونده رو مقداردهی کن (که یه بار صداش میکنه):
container.read(myListener); // فقط دارت
CapsuleContainerProvider.containerOf(context).read(myListener) // فلاتراما کد بالا اونطور که انتظار داری کار نمیکنه؛
شنونده یه بار فراخوانی میشه،
ولی دیگه هیچوقت دوباره فراخوانی نمیشه.
داره چی میگذره؟
نکته کلیدی اینجاست که myListener از یه اثر جانبی (print()) استفاده میکنه
که ReArch ازش خبر نداره چون از طریق یه اثر use.xyz ثبت نشده.
داخلاً، ReArch یادش میمونه که کدوم کپسولها از اثرات جانبی استفاده میکنن و از این اطلاعات برای فعال کردن
بهینهسازیهای مهمی استفاده میکنه، بهخصوص جمعآوری زباله ایدمپوتنت (idempotent garbage collection).
بهطور خلاصه، توی مثال بالا،
وقتی foobarCapsule داده جدید منتشر میکنه،
myListener بهصورت خودکار حذف میشه (بهجای اینکه بازسازی بشه) چون هیچ تقاضایی نداره.
یه کپسول وقتی تقاضا داره که خودش یا یکی از وابستههاش یه اثر جانبی ثبت کنه
(که شامل گوش دادن توسط یه ویجت که بخشی از UI هست هم میشه).
پس راهحل اینجا سادهست: چون توی myListener از یه اثر جانبی استفاده میکنیم
که ReArch ازش خبر نداره، بیایم به ReArch بگیم که داریم از یه اثر جانبی استفاده میکنیم!
میتونی هر اثر جانبی تصادفیای رو ثبت کنی،
ولی یه اثر جانبی no-op داخلی وجود داره که یه کپسول رو بهعنوان شنونده اعلام میکنه
(و چون یه اثر جانبیه، جمعآوری زباله رو غیرفعال میکنه).
/// نسخه اصلاحشده شنونده که یه اثر جانبی ثبت میکنه
/// تا بهصورت خودکار حذف نشه.
void myListener(CapsuleHandle use) {
use.asListener();
print(use(foobarCapsule));
}
// و در نهایت شنونده رو یه جایی نزدیک شروع اپلیکیشنت مقداردهی کن.
container.read(myListener); // فقط دارت
CapsuleContainerProvider.containerOf(context).read(myListener) // فلاترCapsuleContainerProvider.containerOf() یه متد خاص فلاتره که
کانتینر اپلیکیشن در حال اجرا رو میگیره.
استفاده از این تابع برای مقداردهی شنوندهها اشکالی نداره، ولی برای تقریباً هیچ چیز دیگهای نباید استفاده بشه.
(همچنین بهعنوان یه راه فرار برای وقتی که با یه سری API خارجی کار میکنی
که با واکنشپذیری ReArch خوب بازی نمیکنن عمل میکنه.)
از اونجایی که استفاده از CapsuleContainerProvider.containerOf توی تقریباً همه موقعیتها توصیه نمیشه،
میتونی با روش زیر هم شنوندهها رو مقداردهی کنی:
class InitializeListeners extends RearchConsumer {
const InitializeListeners({required this.child, super.key});
final Widget child;
Widget build(BuildContext context, WidgetHandle use) {
use(myListener);
return child;
}
}و یه ویجت InitializeListeners درست زیر RearchBootstrapper بندازی.
اگه به کد اعلانی (declarative) خیلی مقیدی، این یه روش جایگزین براته
که اپلیکیشنت رو بهصورت اعلانی مقداردهی کنی
و از استفاده از CapsuleContainerProvider.containerOf() پرهیز کنی.
