BLoC Pattern
ตัวอย่างการใช้งาน BLoC Pattern โดยใช้ Library ชื่อ flutter_bloc
โครงสร้างแอปโดยสมมุติ
- App -> (context ของ App ถูกส่งไปที่ HomeScreen โดยที่มี BLoC ส่งไปด้วย)
- HomeScreen -> (context ของ App และ HomeScreen ถูกส่งไปที่ ContainerX โดยที่มี BLoC ส่งไปด้วย)
- ContainerX
ไฟล์ app.dart
void main() { // ให้ userRepository เป็นจุดเริ่มต้นทุกอย่างใน App อาจจะเป็น Object ที่ใช้ในการเชื่อมต่อฐานข้อมูล หรือเรียก APIs ก็ได้ // ในกรณี Firestore ก็อาจจะเป็น Firestore.instance final userRepository = ...; runApp( // ครอบ BLoC ชั้นแรกด้วย AuthenticationBloc BlocProvider<AuthenticationBloc>( create: (context) { // สร้าง AuthenticationBloc() ขึ้นมาใหม่ตัวนึงส่งค่า userRepository เข้าไปเช็ค Business Logic และ .... // ทำการส่ง Event ไปให้ BLoC เพื่อเริ่มการทำงานของ BLoC โดย BLoC ทำงานเป็น Stream มันจะทำงานเช็ค Event เรื่อยๆ เพื่อให้ได้ state กลับมาเรื่อยๆ // และเราจะใช้ state นั้นในการกำหนดว่า App เราควรแสดงผลอะไร (Declarative style) return AuthenticationBloc(userRepository: userRepository) ..add(AppStarted()); }, // context ที่ส่งไปใน App() จะถูกแนบไปด้วย AuthenticationBloc ทีอยู่ในสถานะ AppStarted() child: App(userRepository: userRepository), ), ); } class App extends StatelessWidget { final OdooClient userRepository; App({Key key, @required this.userRepository}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( home: BlocBuilder<AuthenticationBloc, AuthenticationState>( builder: (context, state) { if (state is AuthenticationUninitialized) { return SplashPage(); } if (state is AuthenticationAuthenticated) { return HomeScreen(userRepository: userRepository); } if (state is AuthenticationUnauthenticated) { return LoginScreen(userRepository: userRepository); } if (state is AuthenticationLoading) { return LoadingIndicator(); } return SplashPage(); }, ), ); } }
ไฟล์ HomeScreen.dart
class HomeScreen extends StatefulWidget { final OdooClient _userRepository; HomeScreen({ @required Key key, @required userRepository, }) : assert(userRepository != null), _userRepository = userRepository, super(key: key); State<HomeScreen> createState() => _HomeScreen(); } class _HomeScreen extends State<HomeScreen> { OdooClient get _userRepository => widget._userRepository; OdooUser get _odooUser => widget._userRepository.odooUser; @override void initState() { super.initState(); } @override Widget build(BuildContext context) { // นอกจาก BlocProvider ที่ใช้ฝัง BLoC เข้าไปใน context แล้วเรายังใข้ MultiBlocProvider ในการฝัง BLoC หลายๆชนิด เข้าไปใน context ได้อีก // ซึ่ง BLoC [FetchUserBloc, FetchWorkOrderBloc] จะเอาไว้ใช้ใน WorkOrderScreen() อีกที return MultiBlocProvider( providers: [ BlocProvider<FetchUserBloc>( create: (BuildContext context) => FetchUserBloc(odooUser: _odooUser)..add(FetchUserStarted()), ), BlocProvider<FetchWorkOrderBloc>( create: (BuildContext context) => FetchWorkOrderBloc(odooClient: _userRepository)..add(FetchWorkOrderStarted()), ), ], child: ContainerX() ); } }
ไฟล์ container_x.dart
class ContainerX extends StatefulWidget { @override State<ContainerX> createState() => _ContainerX(); } class _ContainerX extends State<ContainerX> { @override Widget build(BuildContext context) { // ประกาศวิตเจตเก็บไว้ชื่อ _Container // วิตเจตนี้ใช้ BlocBuilder ในการสร้างวิตเจตอีกที Widget _Container = BlocBuilder<FetchUserBloc, FetchDataState>( // BlocBuilder นี้รับ BLoC ประเภท FetchUserBloc ที่อยู่ใน context วิตเจตต้นทาง bloc: BlocProvider.of<FetchUserBloc>(context), // ตัวสร้าง Widget โดยส่ง state มาให้ builder: (context, state) { // อยู่ในขั้นตอนการเช็ก state ของ BLoC นี้เพื่อดูว่าควรจะ return วิตเจตไหนออกไปดี if(state is FetchUserSuccess) { return Container( child: StreamBuilder( stream: state.info(), builder: (context, snapshot) { if(snapshot.hasError) { return Text('SnapShot Error'); } else if(snapshot.hasData) { print(snapshot.data); return Text(snapshot.data['name']); } else { return Text("Loading ... in Stream Builder"); } }, ) ); } else if(state is FetchUserFailed) { return Container( child: Text('Failed') ); } else { return Container( child: Text('Loading ...') ); } }, ); return _Container; } }
Top comments (0)