[ Flutter / 플러터 ] Bloc 패턴 왜 써야 하는가? - YouTube

 

 

1. CountBloc.dart

import "dart:async";

class CountBloc {
  int _count = 0;
  final StreamController<int> _countStream = StreamController<int>();
  Stream<int> get count => _countStream.stream;

  CountEventBloc countEventBloc = CountEventBloc();

  CountBloc() {
    countEventBloc._countEventStream.stream.listen((event) {
      switch (event) {
        case CountEvent.EVENT_PLUS:
          _count++;
          break;

        case CountEvent.EVENT_MINUS :
          _count--;
          break;
      }
      _countStream.sink.add(_count);
    });
  }

  dispose () {
    _countStream.close();
    countEventBloc.dispose();
  }
}

class CountEventBloc {
  final StreamController<CountEvent> _countEventStream = StreamController<CountEvent>();

  Sink<CountEvent> get countEventSink => _countEventStream.sink;

  dispose() {
    _countEventStream.close();
  }
}

enum CountEvent {EVENT_PLUS, EVENT_MINUS}

 

2. CountView.dart

import "package:flutter/material.dart";
import "package:bloc/CountBloc.dart";

class CountView extends StatelessWidget {
  final CountBloc countBloc;

  const CountView({super.key, required this.countBloc});

  @override
  Widget build(BuildContext context) {
    print("CountView Build!!");

    return Center(
      child: StreamBuilder(
        stream: countBloc.count,
        initialData: 0,
        builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
          if (snapshot.hasData) {
            return Text(snapshot.data.toString(), style: const TextStyle(fontSize: 80),);
          }

          return const CircularProgressIndicator();
        },
      ),
    );
  }
}

 

3. main.dart

import "package:flutter/material.dart";
import "package:bloc/CountBloc.dart";
import "package:bloc/CountView.dart";

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Bloc Sample",
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: const BlocMain(title: "Bloc Main Page"),
    );
  }
}

class BlocMain extends StatefulWidget {
  const BlocMain({super.key, required this.title});

  final String title;

  @override
  State<BlocMain> createState() => _BlocMain();
}

class _BlocMain extends State<BlocMain> {
  late final CountBloc countBloc;

  @override
  void initState() {
    super.initState();
    countBloc = CountBloc();
  }

  @override
  void dispose() {
    super.dispose();
    countBloc.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(widget.title)),
      body: CountView(countBloc: countBloc),
      floatingActionButton: Row(
        mainAxisAlignment: MainAxisAlignment.end,
        children: <Widget>[
          IconButton(onPressed: () {
            countBloc.countEventBloc.countEventSink.add(CountEvent.EVENT_PLUS);
          }, icon: const Icon(Icons.add)),
          IconButton(onPressed: () {
            countBloc.countEventBloc.countEventSink.add(CountEvent.EVENT_MINUS);
          }, icon: const Icon(Icons.remove))
        ],
      ),
    );
  }
}

 

 

카운트위젯생성시 한번만 build가 호출되고, count 더하기, 빼기 시에는 호출되지 않는다.

 

 

위와 같은 Bloc구조는 관리해야할 파일이 많아지므로 

CountEventBloc를 생략하고

CountBloc Class에 plus, minus Method를 만들어 바로 count를 + - 하여 _countStream.sink.add(_count);호출 하도록 만들고

UI에서는 countBloc.plus() 혹은 countBloc.minus()로 바로 이벤트 없이 호출하여 단순화 시킬수 도 있다.