flutter에서 Bloc 적용하기

오늘은 flutter 프로젝트에서 bloc 구조로 만드는 방법을 작성하려 합니다.

Bloc 구조는 인터페이스와 데이터를 처리하는 프로그램 로직을 분리하여 반응형 프로그래밍을 할 때 사용합니다.

pubspec.yaml 작성하기

dependencies:
  flutter:
    sdk: flutter
  flutter_bloc:

flutter로 작성된 앱의 구조를 bloc 으로 만들기 위해 flutter_bloc 패키지를 추가해줍니다.

main.dart 앱 코드 작성하기

이제 앱 코드를 보겠습니다.

import 'package:flutter/material.dart';
import 'package:bloc/bloc.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

머티리얼 디자인의 앱을 만들기 위한 material 패키지와 bloc 구조를 위한 flutter_bloc과 bloc 패키지도 가져옵니다.

enum CounterEvent { increment, decrement }

열거형을 이용하여 묶어줍니다.

class BlocDelegateClass extends BlocDelegate {
  @override
  void onTransition(Transition transition) {}
}

이벤트가 전달되고, bloc이 업데이트되기 전에 불러오는 onTransition 메소드를 오버라이드해줍니다.

때에 따라서 onTransition 메소드에서 원하는 기능을 구현할 수 있습니다.

void main() {
  BlocSupervisor().delegate = BlocDelegateClass();
  runApp(MyApp());
}

BlocDelegate 객체가 BlocSupervisor에서 위임을 받아 Blocs의 이벤트들을 처리합니다.

class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _MyAppState();
}

StatefulWidget으로 버튼, 슬라이더, 체크 박스처럼 사용자와 상호작용하여 위젯이 변화하는 것을 묶어줍니다.

createState 메소드를 오버라이딩하여 _MyAppState 객체를 생성해줍니다.

class CounterBloc extends Bloc<CounterEvent, int> {
  @override
  get initialState => 0;

initialState를 오버라이드하여 이벤트가 처리되기 전의 상태를 0으로 초기화해줍니다.

  @override
  Stream<int> mapEventToState(currentState, event) async* {
    switch (event) {
      case CounterEvent.increment:
        yield currentState + 1;
        break;
      case CounterEvent.decrement:
        yield currentState - 1;
        break;
    }
  }
}

Bloc 클래스를 확장할 때에 mapEventToState 메소드를 오버라이드하여 presentation 레이어가 이벤트를 전달해줄 때마다 switch문에 의해 비동기 Stream 형식으로 상태를 반환합니다.

class _MyAppState extends State<MyApp> {
  final _counterBloc = CounterBloc();

Bloc을 확장한 CounterBloc 객체를 만들어줍니다.

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'bloc code',
      home: BlocProvider(
        bloc: _counterBloc,
        child: MyappPage(),
      ),
    );
  }
}

BlocProvider는 CounterBloc 객체를 하위 위젯 트리에 제공해줍니다.

class MyappPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final _counterBloc = BlocProvider.of<CounterBloc>(context);

BlocProvider.of로 Bloc을 전달받게 됩니다.

    return Scaffold(
      body: BlocBuilder(
        bloc: _counterBloc,
        builder: (context, count) {
          return Center(child: Text(count.toString()));
        },
      ),

StreamBuilder처럼 비동기로 들어오는 상태를 위젯으로 그려줍니다.

위 코드에서는 Center와 Text 생성자로 인하여 가운데에 count 상태가 문자열로 출력됩니다.

      floatingActionButton: Column(
        mainAxisAlignment: MainAxisAlignment.end,
        children: [
          FloatingActionButton(
            child: Icon(Icons.add),
            onPressed: () {
              _counterBloc.dispatch(CounterEvent.increment);
            },
          ),

floating 버튼을 만들어줍니다.

이 버튼이 눌리면 mapEventToState를 반응하게 만들어서 increment라는 이벤트로 Bloc에 통지해줍니다.

          FloatingActionButton(
            child: Icon(Icons.remove),
            onPressed: () {
              _counterBloc.dispatch(CounterEvent.decrement);
            },
          ),
        ],
      ),
    );
  }
}

floating 버튼을 하나 더 만들어줍니다.

이 버튼이 눌리면 mapEventToState를 반응하게 만들어서 decrement라는 이벤트로 Bloc에 통지해줍니다.

Written on February 11, 2019