BLoC (Business Logic Component) — الگوی مدیریت وضعیت برای Flutter است که توسط Google در سال ۲۰۱۸ در DartConf معرفی شد. BLoC منطق کسبوکار و رابط کاربری را از طریق جریانهای واکنشی (Stream) جدا میکند: UI رویداد (Event) ارسال میکند، BLoC آن را پردازش میکند و وضعیت (State) جدید را از طریق Stream برمیگرداند. به گزارش pub.dev، بسته flutter_bloc بیش از ۱۱ هزار لایک دریافت کرده و در هزاران برنامه Flutter استفاده میشود.
نکات اصلی
BLoC (Business Logic Component) — الگوی معماری برای Flutter است که در آن منطق کسبوکار در یک کلاس جداگانه، جدا از UI قرار میگیرد. BLoC دادههای ورودی را از طریق جریان رویدادها (Event) دریافت کرده و دادههای خروجی را از طریق جریان وضعیتها (State) تولید میکند. لایه نمایش (Widget) فقط مشترک جریان State میشود و UI را نمایش میدهد، بدون اینکه هرگز منطق کسبوکار را مستقیماً اجرا کند.
مفهوم BLoC بر اساس برنامهنویسی واکنشی و الگوی Observer است. هر کامپوننت BLoC یک ماژول جداگانه با قرارداد مشخص است: مجموعه Event (چه چیزی ممکن است رخ دهد) و مجموعه State (چه چیزی ممکن است نمایش داده شود) مشخص هستند. توسعهدهنده نمیتواند "تصادفی" وضعیت را از UI تغییر دهد — فقط از طریق Event خاص. این کار کد را قابل پیشبینی و قابل تست میکند.
بر اساس نظرسنجی Flutter Community 2025، BLoC پس از Provider در رتبه دوم محبوبیت در میان راهحلهای مدیریت وضعیت در Flutter قرار دارد. مزایای اصلی: تایپبندی دقیق، جداسازی منطق، پشتیبانی داخلی Stream، اکوسیستم غنی ابزارها (BlocProvider، BlocListener، BlocSelector).
معماری BLoC حول سه موجودیت ساخته شده است: Event (ورودی)، Bloc (پردازشگر) و State (خروجی). Widget رویداد را از طریق متد add() ارسال میکند. Bloc رویداد را در متد mapEventToState یا on<Event> دریافت میکند، منطق کسبوکار را اجرا کرده و State جدید را از طریق yield تولید میکند. Widget State را از طریق Stream دریافت کرده و دوباره رندر میکند.
abstract class CounterEvent {}
class Increment extends CounterEvent {}
class Decrement extends CounterEvent {}
class CounterBloc extends Bloc<CounterEvent, int> {
CounterBloc() : super(0);
@override
Stream<int> mapEventToState(CounterEvent event) async* {
if (event is Increment) {
yield state + 1;
} else if (event is Decrement) {
yield state - 1;
}
}
}ایمنی نوع: Bloc با دو نوع پارامتر شده است — Event و State. کامپایلر Dart بررسی میکند که Widget فقط Eventهای اعلام شده را فراخوانی کند و Bloc فقط Stateهای اعلام شده را برگرداند. خطاهای زمان اجرا از نوع "Action ناشناخته" حذف شدهاند.
Close و Dispose: Bloc اینترفیس Closeable را پیادهسازی میکند. هنگام نابود شدن ویجت، Bloc به طور خودکار Stream را از طریق متد close() میبندد. نشت اشتراکهای واکنشی غیرممکن است — BlocProvider چرخه حیات Bloc را مدیریت کرده و آن را به Route یا صفحه متصل میکند.
Cubit — پیادهسازی سادهشده Bloc بدون Event است که در بسته flutter_bloc 6.0 معرفی شد. Cubit به جای کلاسهای Event مستقیماً متدها را اعلام میکند: increment()، fetchData(). در داخل، Cubit از همان مکانیزم Stream استفاده میکند اما لایه Event را پنهان میکند. این کار کد اضافی (boilerplate) را برای سناریوهای ساده ۴۰-۵۰٪ کاهش میدهد.
| ویژگی | Bloc | Cubit |
|---|---|---|
| کلاسهای Event | اجباری | نیاز نیست |
| کد اضافی (Boilerplate) | زیاد | کم |
| ردیابی Action | از طریق نوع Event | فقط نام متد |
| مناسب برای | سناریوهای پیچیده | وضعیتهای ساده |
| تحلیل | خودکار بر اساس Event | دستی |
چه موقع Cubit انتخاب کنیم: وضعیت با ۲-۳ گزینه (loading، loaded، error)، فرمهای ساده، شمارندهها، وضعیتهای UI (باز/بسته). چه موقع Bloc: منطق کسبوکار پیچیده با اقدامات متعدد: ثبت سفارش، احراز هویت، همگامسازی داده. Bloc ردیابی دقیق هر اقدام را از طریق Event فراهم میکند — هر فراخوانی در BlocObserver ثبت میشود.
BlocObserver — ناظر سراسری که تمام Bloc و Cubitها را در برنامه ردیابی میکند. امکان ثبت Event، State، خطاها و انتقالها را فراهم میکند. کافی است یک نمونه را متصل کنید: Bloc.observer = AppBlocObserver()، و تمام ردیابی وضعیت برنامه به صورت متمرکز در دسترس است.
BlocProvider — InheritedWidget از flutter_bloc است که Bloc را در اختیار ویجتهای فرزند قرار میدهد. هنگام مقداردهی اولیه ویجت، BlocProvider یک Bloc ایجاد میکند و هنگام نابودی، به طور خودکار آن را از طریق close() میبندد. BlocProvider میتواند در سطح MaterialApp (Bloc سراسری) یا در سطح یک Route خاص (Bloc محلی) قرار گیرد.
BlocProvider(
create: (context) => CounterBloc(),
child: Column(
children: [
BlocBuilder<CounterBloc, int>(
builder: (context, state) => Text('$state'),
),
ElevatedButton(
onPressed: () => context.read<CounterBloc>().add(Increment()),
child: Text('+'),
),
],
),
)BlocBuilder — ویجتی که UI را با هر State جدید بازسازی میکند. BlocListener — برای اثرات جانبی (یک بار پردازش State بدون بازسازی UI): نمایش SnackBar، ناوبری به صفحه دیگر. BlocConsumer — ترکیب Builder و Listener برای مواردی که هم بازسازی و هم اثر جانبی نیاز است. BlocSelector — برای بازسازی انتخابی فقط هنگام تغییر یک فیلد خاص از State.
MultiBlocProvider — ویجتی برای BlocProviderهای تو در تو بدون افزایش سطح تو رفتگی. برنامه Flutter با ۱۰-۱۵ Bloc از MultiBlocProvider در سطح ریشه برای ثبت تمام Blocهای قابل دسترس در کل برنامه استفاده میکند: AuthenticationBloc، CartBloc، SettingsBloc.
BLoC تست میشود به صورت مجزا بدون ویجتهای Flutter. کافی است بسته Dart flutter_test و بسته bloc_test را ایمپورت کنید. سناریوی تست: ایجاد Bloc، اضافه کردن Event، بررسی State. blocTest — ابزاری که توالی build → act → expect را خودکار میکند.
blocTest<CounterBloc, int>(
'emits [1] when Increment is added',
build: () => CounterBloc(),
act: (bloc) => bloc.add(Increment()),
expect: () => [1],
)Mocking: BLoC که به مخزن یا API وابسته است با mock از طریق mocktail تست میشود. مخزن در سطح انتزاع mock میشود، Bloc وابستگیهای mock شده را از طریق سازنده دریافت میکند. Hydrated Bloc — افزونهای برای ذخیره/بازیابی خودکار وضعیت در حافظه محلی. با HydratedBlocStorage و حافظه فایل موقت تست میشود.
پوشهها و فایلها: ساختار معمول پروژه Flutter با BLoC: bloc/counter_bloc.dart، bloc/counter_event.dart، bloc/counter_state.dart. برای ۳۰+ صفحه، گروهبندی بر اساس ویژگیها توصیه میشود: features/auth/bloc/، features/cart/bloc/. هر Bloc یک فایل جداگانه، هر Event و State — یا در فایلهای جداگانه یا در یک فایل با Bloc.
عملکرد: BLoC سرباری روی Streamهای خالی ایجاد نمیکند. BlocBuilder از buildWhen برای فیلتر کردن بازسازیها استفاده میکند — ویجت فقط هنگام تغییر شرط خاص بهروزرسانی میشود. Close تضمین میکند که Blocهای غیرفعال حافظه مصرف نمیکنند. بر اساس Flutter DevTools، BLoC کمتر از ۱٪ به اندازه باندل اضافه میکند.
مهاجرت از Provider: BLoC به راحتی در یک پروژه با Provider همزیستی میکند. مهاجرت تدریجی: ابتدا پیچیدهترین Providerها با Bloc جایگزین میشوند، سپس بقیه. BlocProvider با درخت Provider سازگار است: ویجتهای قدیمی میتوانند از Provider استفاده کنند، ویجتهای جدید — از BlocProvider، در یک برنامه.
سوالات متداول
BLoC از Event + Stream برای جداسازی منطق کسبوکار و تایپبندی دقیق استفاده میکند. Provider — لایهای روی InheritedWidget برای تزریق ساده وابستگیها و ChangeNotifier. BLoC برای سناریوهای پیچیده با وضعیتهای متعدد مناسبتر است، Provider — برای وضعیت UI محلی. BLoC به کد اضافی بیشتری نیاز دارد اما قابلیت ردیابی کامل از طریق Event را فراهم میکند.
Hydrated Bloc — افزونهای از بسته hydrated_bloc که آخرین State را به طور خودکار در حافظه محلی (پیشفرض Hive) ذخیره میکند. هنگام راهاندازی مجدد برنامه، Bloc وضعیت ذخیره شده را به جای وضعیت اولیه بازیابی میکند. این کار مسئله پایداری را بدون فراخوانی دستی ذخیرهسازی حل میکند: ورود، سبد خرید، تنظیمات به طور خودکار بین جلسات ذخیره میشوند.
خطا در BLoC از طریق try-catch داخل mapEventToState یا on<Event> مدیریت میشود. هنگام خطا، Bloc State خطا را برمیگرداند: yield LoadError(error.message). در UI، BlocListener یا BlocConsumer State را از نظر نوع خطا بررسی کرده و SnackBar یا دیالوگ نشان میدهد. BlocObserver تمام استثناهای مدیریتنشده را به صورت سراسری ثبت میکند.
BLoC — الگوی مخصوص Flutter است، زیرا از Dart Stream و ویجتهای Flutter استفاده میکند. مفهوم Event → Bloc → State میتواند برای AngularDart و Server-side Dart تطبیق داده شود، اما اکوسیستم اصلی (BlocProvider، BlocBuilder، BlocObserver) به Flutter وابسته است. برای React Native از Redux یا MobX استفاده کنید، برای SwiftUI — Combine + MVVM.
Cubit — برای وضعیتهای ساده (شمارنده، toggle، فرم با ۲-۳ فیلد). Bloc — برای منطق پیچیده (فید خبری، ثبت سفارش، احراز هویت). قانون اصلی: اگر ردیابی هر اقدام (Event) برای تحلیل یا اشکالزدایی نیاز است — Bloc. اگر متدهای تغییردهنده وضعیت کافی هستند — Cubit. هر دو الگو در یک پروژه همزیستی میکنند.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.