DEV Community

Perm Chao
Perm Chao

Posted on

2 1

ลองแบบมั่วๆกับ flutter_bloc

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();
        },
      ),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

ไฟล์ 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()
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

ไฟล์ 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;
  }
}
Enter fullscreen mode Exit fullscreen mode

Heroku

This site is built on Heroku

Join the ranks of developers at Salesforce, Airbase, DEV, and more who deploy their mission critical applications on Heroku. Sign up today and launch your first app!

Get Started

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay