BLoC — چیست، Business Logic Component در Flutter

نویسنده: IT Sectr منتشر شده: 2026-02-19 زمان مطالعه: 7 دقیقه

BLoC (Business Logic Component) — الگوی مدیریت وضعیت برای Flutter است که توسط Google در سال ۲۰۱۸ در DartConf معرفی شد. BLoC منطق کسب‌وکار و رابط کاربری را از طریق جریان‌های واکنشی (Stream) جدا می‌کند: UI رویداد (Event) ارسال می‌کند، BLoC آن را پردازش می‌کند و وضعیت (State) جدید را از طریق Stream برمی‌گرداند. به گزارش pub.dev، بسته flutter_bloc بیش از ۱۱ هزار لایک دریافت کرده و در هزاران برنامه Flutter استفاده می‌شود.

نکات اصلی

  • Event — سیگنال ورودی توصیف‌کننده عمل: کلیک دکمه، بارگذاری داده
  • State — وضعیت خروجی UI: داده بارگذاری شد، خطا، در حال بارگذاری
  • Bloc — کلاس اصلی که Event را دریافت کرده و State را از طریق Stream برمی‌گرداند
  • Cubit — نسخه ساده‌شده Bloc بدون Event که توابع را مستقیماً فراخوانی می‌کند
  • BlocProvider — ویجت Flutter برای تزریق Bloc به درخت ویجت‌ها

BLoC چیست؟

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

معماری BLoC حول سه موجودیت ساخته شده است: Event (ورودی)، Bloc (پردازشگر) و State (خروجی). Widget رویداد را از طریق متد add() ارسال می‌کند. Bloc رویداد را در متد mapEventToState یا on<Event> دریافت می‌کند، منطق کسب‌وکار را اجرا کرده و State جدید را از طریق yield تولید می‌کند. Widget State را از طریق Stream دریافت کرده و دوباره رندر می‌کند.

Dart
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 یا صفحه متصل می‌کند.

مقایسه Bloc و Cubit

Cubit — پیاده‌سازی ساده‌شده Bloc بدون Event است که در بسته flutter_bloc 6.0 معرفی شد. Cubit به جای کلاس‌های Event مستقیماً متدها را اعلام می‌کند: increment()، fetchData(). در داخل، Cubit از همان مکانیزم Stream استفاده می‌کند اما لایه Event را پنهان می‌کند. این کار کد اضافی (boilerplate) را برای سناریوهای ساده ۴۰-۵۰٪ کاهش می‌دهد.

ویژگیBlocCubit
کلاس‌های Eventاجبارینیاز نیست
کد اضافی (Boilerplate)زیادکم
ردیابی Actionاز طریق نوع Eventفقط نام متد
مناسب برایسناریوهای پیچیدهوضعیت‌های ساده
تحلیلخودکار بر اساس Eventدستی

چه موقع Cubit انتخاب کنیم: وضعیت با ۲-۳ گزینه (loading، loaded، error)، فرم‌های ساده، شمارنده‌ها، وضعیت‌های UI (باز/بسته). چه موقع Bloc: منطق کسب‌وکار پیچیده با اقدامات متعدد: ثبت سفارش، احراز هویت، همگام‌سازی داده. Bloc ردیابی دقیق هر اقدام را از طریق Event فراهم می‌کند — هر فراخوانی در BlocObserver ثبت می‌شود.

BlocObserver — ناظر سراسری که تمام Bloc و Cubit‌ها را در برنامه ردیابی می‌کند. امکان ثبت Event، State، خطاها و انتقال‌ها را فراهم می‌کند. کافی است یک نمونه را متصل کنید: Bloc.observer = AppBlocObserver()، و تمام ردیابی وضعیت برنامه به صورت متمرکز در دسترس است.

BlocProvider و BlocBuilder

BlocProvider — InheritedWidget از flutter_bloc است که Bloc را در اختیار ویجت‌های فرزند قرار می‌دهد. هنگام مقداردهی اولیه ویجت، BlocProvider یک Bloc ایجاد می‌کند و هنگام نابودی، به طور خودکار آن را از طریق close() می‌بندد. BlocProvider می‌تواند در سطح MaterialApp (Bloc سراسری) یا در سطح یک Route خاص (Bloc محلی) قرار گیرد.

Dart
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

BLoC تست می‌شود به صورت مجزا بدون ویجت‌های Flutter. کافی است بسته Dart flutter_test و بسته bloc_test را ایمپورت کنید. سناریوی تست: ایجاد Bloc، اضافه کردن Event، بررسی State. blocTest — ابزاری که توالی build → act → expect را خودکار می‌کند.

Dart
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 و حافظه فایل موقت تست می‌شود.

BLoC در تولید

پوشه‌ها و فایل‌ها: ساختار معمول پروژه 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 با Provider در Flutter چیست؟

BLoC از Event + Stream برای جداسازی منطق کسب‌وکار و تایپ‌بندی دقیق استفاده می‌کند. Provider — لایه‌ای روی InheritedWidget برای تزریق ساده وابستگی‌ها و ChangeNotifier. BLoC برای سناریوهای پیچیده با وضعیت‌های متعدد مناسب‌تر است، Provider — برای وضعیت UI محلی. BLoC به کد اضافی بیشتری نیاز دارد اما قابلیت ردیابی کامل از طریق Event را فراهم می‌کند.

Hydrated Bloc چیست؟

Hydrated Bloc — افزونه‌ای از بسته hydrated_bloc که آخرین State را به طور خودکار در حافظه محلی (پیش‌فرض Hive) ذخیره می‌کند. هنگام راه‌اندازی مجدد برنامه، Bloc وضعیت ذخیره شده را به جای وضعیت اولیه بازیابی می‌کند. این کار مسئله پایداری را بدون فراخوانی دستی ذخیره‌سازی حل می‌کند: ورود، سبد خرید، تنظیمات به طور خودکار بین جلسات ذخیره می‌شوند.

چگونه خطاها را در BLoC مدیریت کنیم؟

خطا در BLoC از طریق try-catch داخل mapEventToState یا on<Event> مدیریت می‌شود. هنگام خطا، Bloc State خطا را برمی‌گرداند: yield LoadError(error.message). در UI، BlocListener یا BlocConsumer State را از نظر نوع خطا بررسی کرده و SnackBar یا دیالوگ نشان می‌دهد. BlocObserver تمام استثناهای مدیریت‌نشده را به صورت سراسری ثبت می‌کند.

آیا می‌توان از BLoC با فریم‌ورک‌های دیگر استفاده کرد؟

BLoC — الگوی مخصوص Flutter است، زیرا از Dart Stream و ویجت‌های Flutter استفاده می‌کند. مفهوم Event → Bloc → State می‌تواند برای AngularDart و Server-side Dart تطبیق داده شود، اما اکوسیستم اصلی (BlocProvider، BlocBuilder، BlocObserver) به Flutter وابسته است. برای React Native از Redux یا MobX استفاده کنید، برای SwiftUI — Combine + MVVM.

چه چیزی را انتخاب کنیم: Bloc یا Cubit؟

Cubit — برای وضعیت‌های ساده (شمارنده، toggle، فرم با ۲-۳ فیلد). Bloc — برای منطق پیچیده (فید خبری، ثبت سفارش، احراز هویت). قانون اصلی: اگر ردیابی هر اقدام (Event) برای تحلیل یا اشکال‌زدایی نیاز است — Bloc. اگر متدهای تغییردهنده وضعیت کافی هستند — Cubit. هر دو الگو در یک پروژه همزیستی می‌کنند.

خلاصه

  • BLoC — الگوی مدیریت وضعیت Flutter از طریق Event → Stream → State
  • Event — عمل (کلیک، بارگذاری)، State — واکنش (داده، خطا، بارگذاری)
  • Cubit — نسخه ساده‌شده بدون Event، تا ۵۰٪ کد اضافی کمتر
  • BlocProvider — تزریق Bloc به درخت ویجت با close خودکار
  • BlocObserver — نظارت سراسری تمام Bloc و Cubit‌ها در برنامه
  • Hydrated Bloc — ذخیره خودکار وضعیت از طریق Hive
  • blocTest — ابزار تست واحد Bloc با جداسازی از Flutter

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید