BLoC — คืออะไร Business Logic Component ใน Flutter

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-02-19 เวลาอ่าน: 7 นาที

BLoC (Business Logic Component) — รูปแบบการจัดการสถานะสำหรับ Flutter ที่ Google นำเสนอในปี 2018 ที่ DartConf BLoC แยกตรรกะทางธุรกิจออกจากส่วนติดต่อผู้ใช้ผ่านสตรีมเชิงปฏิกิริยา (Stream): UI ส่ง Event, BLoC ประมวลผลและส่งคืน State ใหม่ผ่าน Stream ตาม pub.dev แพ็คเกจ flutter_bloc ได้รับมากกว่า 11,000 ไลก์และถูกใช้ในแอปพลิเคชัน 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 อยู่ในอันดับสองในด้านความนิยมในโซลูชันการจัดการสถานะใน Flutter รองจาก Provider ข้อดีหลัก: การกำหนดชนิดที่เข้มงวด, การแยกตรรกะ, การรองรับ Stream ในตัว, ระบบนิเวศของยูทิลิตี้ที่หลากหลาย (BlocProvider, BlocListener, BlocSelector)

สถาปัตยกรรม BLoC: Event → Bloc → State

สถาปัตยกรรม BLoC สร้างขึ้นรอบสามเอนทิตี: Event (นำเข้า), Bloc (ตัวจัดการ) และ State (ส่งออก) Widget ส่ง Event ผ่านเมธอด add() Bloc รับ Event ในเมธอด 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 ที่ประกาศไว้ ข้อผิดพลาดรันไทม์เช่น "การกระทำที่ไม่รู้จัก" จะถูกกำจัด

Close และ Dispose: Bloc ใช้อินเทอร์เฟส Closeable เมื่อวิดเจ็ตถูกทำลาย Bloc จะปิด Stream โดยอัตโนมัติผ่านเมธอด close() การรั่วไหลของการสมัครสมาชิกเชิงปฏิกิริยาเป็นไปไม่ได้ — BlocProvider จัดการวงจรชีวิตของ Bloc โดยเชื่อมโยงกับเส้นทางหรือหน้า

Bloc และ Cubit: การเปรียบเทียบ

Cubit คือการใช้งาน Bloc แบบง่ายที่ไม่มี Event ซึ่งนำเสนอในแพ็คเกจ flutter_bloc 6.0 Cubit ประกาศเมธอดโดยตรงแทนคลาส Event: increment(), fetchData() ภายใน Cubit ใช้กลไกแบบ Stream เดียวกันแต่ซ่อนชั้น Event ซึ่งช่วยลดโค้ดสำเร็จรูปลง 40-50% สำหรับสถานการณ์ง่าย ๆ

คุณลักษณะBlocCubit
คลาส Eventจำเป็นไม่จำเป็น
โค้ดสำเร็จรูปสูงต่ำ
การติดตามการกระทำผ่านชนิด Eventเฉพาะชื่อเมธอด
เหมาะสำหรับสถานการณ์ซับซ้อนสถานะง่าย
การวิเคราะห์อัตโนมัติผ่าน Eventด้วยตนเอง

เมื่อเลือก Cubit: สถานะที่มี 2-3 รูปแบบ (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 ทั่วโลก) หรือที่ระดับเส้นทางเฉพาะ (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 ที่มี 10-15 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 จะถูกทดสอบด้วยการจำลองผ่าน mocktail พื้นที่เก็บข้อมูลถูกจำลองที่ระดับนามธรรม และ Bloc รับการอ้างอิงที่จำลองผ่านคอนสตรัคเตอร์ Hydrated Bloc — ส่วนขยายสำหรับการคงอยู่/กู้คืนสถานะอัตโนมัติในพื้นที่เก็บข้อมูลท้องถิ่น ทดสอบด้วย HydratedBlocStorage และพื้นที่เก็บไฟล์ชั่วคราว

BLoC ในโปรดักชัน

โฟลเดอร์และไฟล์: โครงสร้างโปรเจกต์ Flutter ทั่วไปกับ BLoC: bloc/counter_bloc.dart, bloc/counter_event.dart, bloc/counter_state.dart สำหรับ 30+ หน้าจอ แนะนำให้จัดกลุ่มตามฟีเจอร์: features/auth/bloc/, features/cart/bloc/ แต่ละ Bloc เป็นไฟล์แยกต่างหาก แต่ละ Event และ State — ในไฟล์แยกหรือในไฟล์เดียวกับ Bloc

ประสิทธิภาพ: BLoC ไม่สร้างโอเวอร์เฮดสำหรับ Stream ที่ว่างเปล่า BlocBuilder ใช้ buildWhen เพื่อกรองการสร้างใหม่ — วิดเจ็ตจะอัปเดตเมื่อเงื่อนไขเฉพาะเปลี่ยนแปลงเท่านั้น Close รับประกันว่า Bloc ที่ไม่ทำงานจะไม่ใช้หน่วยความจำ ตาม Flutter DevTools BLoC เพิ่มน้อยกว่า 1% ให้กับขนาดบันเดิล

การย้ายจาก 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 — สำหรับสถานะง่าย (ตัวนับ, สวิตช์, ฟอร์มที่มี 2-3 ฟิลด์) Bloc — สำหรับตรรกะซับซ้อน (ฟีดข่าว, การประมวลผลคำสั่งซื้อ, การอนุญาต) กฎหลัก: หากคุณต้องการติดตามทุกการกระทำ (Event) สำหรับการวิเคราะห์หรือดีบัก — เลือก Bloc หากเมธอดที่เปลี่ยนสถานะเพียงพอ — เลือก Cubit ทั้งสองรูปแบบสามารถอยู่ร่วมกันในโปรเจกต์เดียวกันได้

สรุป

  • BLoC — รูปแบบการจัดการสถานะ Flutter ผ่าน Event → Stream → State
  • Event — การกระทำ (กด, โหลด), State — การตอบสนอง (ข้อมูล, ข้อผิดพลาด, กำลังโหลด)
  • Cubit — เวอร์ชันย่อที่ไม่มี Event, โค้ดสำเร็จรูปน้อยลงถึง 50%
  • BlocProvider — การฉีด Bloc ในทรีวิดเจ็ตพร้อมการปิดอัตโนมัติ
  • BlocObserver — การตรวจสอบทั่วโลกของ Bloc และ Cubit ทั้งหมดในแอปพลิเคชัน
  • Hydrated Bloc — การคงอยู่สถานะอัตโนมัติผ่าน Hive
  • blocTest — ยูทิลิตี้สำหรับการทดสอบหน่วย Bloc ที่แยกจาก Flutter

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม